Closing price of Google Stock Prediction

1. Problem

Predicting the closing price of a stock is a complex problem because of several challenges. Stock prices are influenced by a multitude of factors such as market trends, Analyzing and incorporating all these factors accurately into a predictive model is a complex task. Market volatility makes predicting stock prices accurately challenging. Data Quality and Quantity, the pursuit of solving this problem is crucial because accurate stock price predictions have significant implications for investors, financial institutions, and businesses. Accurate predictions can aid investors in making informed decisions. The importance of predicting stock prices lies in its implications for investors, financial institutions, and businesses, it can potentially help investors make more informed decisions about buying, selling, or holding stocks, aiding in risk.

2. Data mining Task

In our project, we will use two data mining tasks to help us predict the closing price of a stock. two of the methods you can consider are classification and clustering. For classification, we will train our model to be able to classify the close price based on a set of attributes such as volume, open, high, low, length etc. For clustering, we will partition closing prices into subnets or clusters, where they are similar to prices in cluster but dissimilar to prices in other clusters based on the attributes Low, Heigh, Open, volume, adjClose, adjHigh.

3. Data

Our dataset is from the source: https://www.kaggle.com/datasets/shreenidhihipparagi/google-stock-prediction

Number of Attributes: 14

Number of objects: 1258

Attribute characteristics:

Attribute Name Data Type Description
symbol unique value Name of company
date numeric date: day, month, and year.
close numeric closing price of a stock is the final price at which a stock is traded on a given trading day.
high numeric The highest price at which a stock traded during a specific trading day.
low numeric The lowest price at which a stock traded during a specific trading day.
open numeric The price of a stock at the beginning of a trading day. It’s the price at which the first trade occurred on that day.
Volume numeric The total number of shares traded during a trading day. Volume is a measure of market activity and liquidity for a stock
adjClose numeric The closing price of a stock adjusted for any corporate actions like dividends, stock splits, or other events that could affect the stock price.
adjHigh numeric The highest price of a stock during a trading day, adjusted for any corporate actions
adjLow numeric The lowest price of a stock during a trading day, adjusted for any corporate actions.
adjOpen numeric The opening price of a stock at the beginning of a trading day, adjusted for any corporate actions.
adjVolume numeric The trading volume of a stock adjusted for any corporate actions. This can provide a clearer picture of tranding activity.
divCash Binary The amount of money paid by a company to its shareholders as a portion of its profits. Dividends are typically paid on a per-share basis
s plitFactor Binary If a stock undergoes a stock split, the split factor indicates the ratio by which the shares were split. For instance, a 2-for-1 split means that for every old share, you now have 2 new shares.
# Load necessary packages
if (!require(caret)) {
  install.packages("caret")
}
Loading required package: caret
Loading required package: lattice
if (!require(cluster)) {
  install.packages("cluster")
}
if (!require(fpc)) {
  install.packages("fpc")
}
Loading required package: fpc
Warning: package ‘fpc’ was built under R version 4.3.2
if (!require(ggplot2)) {
  install.packages("ggplot2")
}
library(caret)
library(cluster)
library(fpc)
library(ggplot2)
dataset = read.csv('Google.csv') 
View(dataset)
print(dataset)

we removed the attributes (symbol, divCash, splitFactor) as they have one value only so we do not need them

dataset=dataset[,2:12]

Convert the date column to a date format

dataset$date <- as.Date(dataset$date, format = "%Y-%m-%d %H:%M:%S")
print(dataset)
str(dataset)
'data.frame':   1258 obs. of  11 variables:
 $ date     : Date, format: "2016-06-14" ...
 $ close    : num  718 719 710 692 694 ...
 $ high     : num  722 723 717 709 702 ...
 $ low      : num  713 717 703 688 693 ...
 $ open     : num  716 719 715 709 699 ...
 $ volume   : int  1306065 1214517 1982471 3402357 2082538 1465634 1184318 2171415 4449022 2641085 ...
 $ adjClose : num  718 719 710 692 694 ...
 $ adjHigh  : num  722 723 717 709 702 ...
 $ adjLow   : num  713 717 703 688 693 ...
 $ adjOpen  : num  716 719 715 709 699 ...
 $ adjVolume: int  1306065 1214517 1982471 3402357 2082538 1465634 1184318 2171415 4449022 2641085 ...
summary(dataset)
      date                close             high       
 Min.   :2016-06-14   Min.   : 668.3   Min.   : 672.3  
 1st Qu.:2017-09-12   1st Qu.: 960.8   1st Qu.: 968.8  
 Median :2018-12-11   Median :1132.5   Median :1143.9  
 Mean   :2018-12-12   Mean   :1216.3   Mean   :1227.4  
 3rd Qu.:2020-03-12   3rd Qu.:1360.6   3rd Qu.:1374.3  
 Max.   :2021-06-11   Max.   :2521.6   Max.   :2527.0  
      low              open          volume           adjClose     
 Min.   : 663.3   Min.   : 671   Min.   : 346753   Min.   : 668.3  
 1st Qu.: 952.2   1st Qu.: 959   1st Qu.:1173522   1st Qu.: 960.8  
 Median :1117.9   Median :1131   Median :1412588   Median :1132.5  
 Mean   :1204.2   Mean   :1215   Mean   :1601590   Mean   :1216.3  
 3rd Qu.:1348.6   3rd Qu.:1361   3rd Qu.:1812156   3rd Qu.:1360.6  
 Max.   :2498.3   Max.   :2525   Max.   :6207027   Max.   :2521.6  
    adjHigh           adjLow          adjOpen       adjVolume      
 Min.   : 672.3   Min.   : 663.3   Min.   : 671   Min.   : 346753  
 1st Qu.: 968.8   1st Qu.: 952.2   1st Qu.: 959   1st Qu.:1173522  
 Median :1143.9   Median :1117.9   Median :1131   Median :1412588  
 Mean   :1227.4   Mean   :1204.2   Mean   :1215   Mean   :1601590  
 3rd Qu.:1374.3   3rd Qu.:1348.6   3rd Qu.:1361   3rd Qu.:1812156  
 Max.   :2527.0   Max.   :2498.3   Max.   :2525   Max.   :6207027  

mean of closing price Using the mean closing price can serve as a basic reference point or a simple benchmark for forecasting future stock prices. The mean closing price is the average price at which a stock has closed over a specific period.

mean(dataset$close)
[1] 1216.317

variance Code

The concept of variance in the context of closing prices for stock prediction serves to quantify the spread or dispersion of the closing prices around their mean or average value. It provides a measure of how much the actual closing prices deviate from the average closing price over a specific period.

var(dataset$close)
[1] 146944.5

Summaries for all numeric attributes and their outliers and boxplots.

#stastistical measures
#summaries
summary(dataset$close)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  668.3   960.8  1132.5  1216.3  1360.6  2521.6 
summary(dataset$high)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  672.3   968.8  1143.9  1227.4  1374.3  2527.0 
summary(dataset$low)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  663.3   952.2  1117.9  1204.2  1348.6  2498.3 
summary(dataset$open)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
    671     959    1131    1215    1361    2525 
summary(dataset$volume)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 346753 1173522 1412588 1601590 1812156 6207027 
summary(dataset$adjClose)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  668.3   960.8  1132.5  1216.3  1360.6  2521.6 
summary(dataset$adjHigh)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  672.3   968.8  1143.9  1227.4  1374.3  2527.0 
summary(dataset$adjLow)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  663.3   952.2  1117.9  1204.2  1348.6  2498.3 
summary(dataset$adjOpen)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
    671     959    1131    1215    1361    2525 
summary(dataset$adjVolume)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 346753 1173522 1412588 1601590 1812156 6207027 
#outliers
boxplot.stats(dataset$close)$out
 [1] 2070.07 2062.37 2098.00 2092.91 2083.51 2095.38 2095.89 2104.11
 [9] 2121.90 2128.31 2117.20 2101.14 2064.88 2070.86 2095.17 2031.36
[17] 2036.86 2081.51 2075.84 2026.71 2049.09 2108.54 2024.17 2052.70
[25] 2055.03 2114.77 2061.92 2066.49 2092.52 2091.08 2036.22 2043.20
[33] 2038.59 2052.96 2045.06 2044.36 2035.55 2055.95 2055.54 2068.63
[41] 2137.75 2225.55 2224.75 2249.68 2265.44 2285.88 2254.79 2267.27
[49] 2254.84 2296.66 2297.76 2302.40 2293.63 2293.29 2267.92 2315.30
[57] 2326.74 2307.12 2379.91 2429.89 2410.12 2395.17 2354.25 2356.74
[65] 2381.35 2398.69 2341.66 2308.76 2239.08 2261.97 2316.16 2321.41
[73] 2303.43 2308.71 2356.09 2345.10 2406.67 2409.07 2433.53 2402.51
[81] 2411.56 2429.81 2421.28 2404.61 2451.76 2466.09 2482.85 2491.40
[89] 2521.60 2513.93
boxplot.stats(dataset$high)$out
 [1] 2116.500 2078.550 2102.510 2123.547 2105.130 2108.370 2102.030
 [8] 2108.820 2152.680 2133.660 2132.735 2130.530 2091.420 2082.010
[15] 2100.780 2094.880 2071.010 2086.520 2104.370 2088.518 2089.240
[22] 2118.110 2128.810 2078.040 2075.000 2125.700 2090.260 2067.060
[29] 2123.560 2109.780 2075.500 2053.100 2057.990 2072.302 2078.210
[36] 2058.870 2050.990 2058.430 2070.780 2093.327 2142.940 2237.310
[43] 2237.660 2255.000 2284.005 2289.040 2275.320 2277.210 2277.990
[50] 2306.597 2306.440 2318.450 2309.600 2295.320 2303.762 2325.820
[57] 2341.260 2337.450 2452.378 2436.520 2427.140 2419.700 2379.260
[64] 2382.200 2382.710 2416.410 2378.000 2322.000 2285.370 2276.601
[71] 2321.140 2323.340 2343.150 2316.760 2360.340 2369.000 2418.480
[78] 2432.890 2442.944 2440.000 2428.140 2437.971 2442.000 2409.745
[85] 2453.859 2468.000 2494.495 2505.000 2523.260 2526.990
boxplot.stats(dataset$low)$out
 [1] 2018.380 2042.590 2059.330 2072.000 2078.540 2063.090 2077.320
 [8] 2083.130 2104.360 2098.920 2103.710 2097.410 2062.140 2002.020
[15] 2038.130 2021.290 2016.060 2046.100 2071.260 2010.000 2020.270
[22] 2046.415 2021.610 2047.830 2033.370 2072.380 2047.550 2043.510
[29] 2070.000 2054.000 2033.550 2017.680 2026.070 2039.220 2041.555
[36] 2010.730 2014.020 2015.620 2044.030 2056.745 2096.890 2151.620
[43] 2214.800 2225.330 2257.680 2253.714 2238.465 2256.090 2249.190
[50] 2266.000 2284.450 2287.845 2271.710 2258.570 2256.450 2278.210
[57] 2313.840 2304.270 2374.850 2402.280 2402.160 2384.500 2311.700
[64] 2351.410 2342.338 2390.000 2334.730 2283.000 2230.050 2242.720
[71] 2283.320 2295.000 2303.160 2263.520 2321.090 2342.370 2360.110
[78] 2402.990 2412.515 2402.000 2407.690 2404.880 2404.200 2382.830
[85] 2417.770 2441.073 2468.240 2487.330 2494.000 2498.290
boxplot.stats(dataset$open)$out
 [1] 2073.000 2068.890 2070.000 2105.910 2078.540 2094.210 2099.510
 [8] 2090.250 2104.360 2100.000 2110.390 2119.270 2067.000 2025.010
[15] 2041.830 2067.450 2050.520 2056.520 2076.190 2067.210 2023.370
[22] 2073.120 2101.130 2070.000 2071.760 2074.060 2085.000 2062.300
[29] 2078.990 2076.030 2061.000 2042.050 2041.840 2051.700 2065.370
[36] 2044.810 2038.860 2027.880 2057.630 2059.120 2097.950 2152.940
[43] 2222.500 2226.130 2277.960 2256.700 2266.250 2261.470 2275.160
[50] 2276.980 2303.000 2291.980 2307.890 2285.250 2293.230 2283.470
[57] 2319.930 2336.000 2407.145 2410.330 2404.490 2402.720 2369.740
[64] 2368.420 2350.640 2400.000 2374.890 2291.860 2261.710 2261.090
[71] 2291.830 2309.320 2336.906 2264.400 2328.040 2365.990 2367.000
[78] 2420.000 2412.835 2436.940 2421.960 2422.000 2435.310 2395.020
[85] 2422.520 2451.320 2479.900 2499.500 2494.010 2524.920
boxplot.stats(dataset$volume)$out
 [1] 3402357 4449022 3530169 3841482 4269902 4745183 3654385 3017947
 [9] 2973891 2965771 3246573 3487056 3160585 3270248 3731589 2921393
[17] 3248393 4626086 3095263 5125791 3142760 4758496 3336352 3360727
[25] 3267883 3029471 3369275 4760260 3088305 3318204 4405584 2950120
[33] 4187586 3880723 3212657 4595891 3552194 6207027 5130576 2833483
[41] 4805752 3316905 3055216 3932954 2867053 2978300 3790618 3365365
[49] 4226748 3700125 4252365 3861489 4233435 3651106 3601750 4044137
[57] 3344450 4081528 3573755 3208495 2951309 3793630 3157875 4267698
[65] 3429036 3581072 3107763 3103882 2888827 4330862 3570927 4016353
[73] 4118170 2986439
boxplot.stats(dataset$adjClose)$out
 [1] 2070.07 2062.37 2098.00 2092.91 2083.51 2095.38 2095.89 2104.11
 [9] 2121.90 2128.31 2117.20 2101.14 2064.88 2070.86 2095.17 2031.36
[17] 2036.86 2081.51 2075.84 2026.71 2049.09 2108.54 2024.17 2052.70
[25] 2055.03 2114.77 2061.92 2066.49 2092.52 2091.08 2036.22 2043.20
[33] 2038.59 2052.96 2045.06 2044.36 2035.55 2055.95 2055.54 2068.63
[41] 2137.75 2225.55 2224.75 2249.68 2265.44 2285.88 2254.79 2267.27
[49] 2254.84 2296.66 2297.76 2302.40 2293.63 2293.29 2267.92 2315.30
[57] 2326.74 2307.12 2379.91 2429.89 2410.12 2395.17 2354.25 2356.74
[65] 2381.35 2398.69 2341.66 2308.76 2239.08 2261.97 2316.16 2321.41
[73] 2303.43 2308.71 2356.09 2345.10 2406.67 2409.07 2433.53 2402.51
[81] 2411.56 2429.81 2421.28 2404.61 2451.76 2466.09 2482.85 2491.40
[89] 2521.60 2513.93
boxplot.stats(dataset$adjHigh)$out
 [1] 2116.500 2078.550 2102.510 2123.547 2105.130 2108.370 2102.030
 [8] 2108.820 2152.680 2133.660 2132.735 2130.530 2091.420 2082.010
[15] 2100.780 2094.880 2071.010 2086.520 2104.370 2088.518 2089.240
[22] 2118.110 2128.810 2078.040 2075.000 2125.700 2090.260 2067.060
[29] 2123.560 2109.780 2075.500 2053.100 2057.990 2072.302 2078.210
[36] 2058.870 2050.990 2058.430 2070.780 2093.327 2142.940 2237.310
[43] 2237.660 2255.000 2284.005 2289.040 2275.320 2277.210 2277.990
[50] 2306.597 2306.440 2318.450 2309.600 2295.320 2303.762 2325.820
[57] 2341.260 2337.450 2452.378 2436.520 2427.140 2419.700 2379.260
[64] 2382.200 2382.710 2416.410 2378.000 2322.000 2285.370 2276.601
[71] 2321.140 2323.340 2343.150 2316.760 2360.340 2369.000 2418.480
[78] 2432.890 2442.944 2440.000 2428.140 2437.971 2442.000 2409.745
[85] 2453.859 2468.000 2494.495 2505.000 2523.260 2526.990
boxplot.stats(dataset$adjLow)$out
 [1] 2018.380 2042.590 2059.330 2072.000 2078.540 2063.090 2077.320
 [8] 2083.130 2104.360 2098.920 2103.710 2097.410 2062.140 2002.020
[15] 2038.130 2021.290 2016.060 2046.100 2071.260 2010.000 2020.270
[22] 2046.415 2021.610 2047.830 2033.370 2072.380 2047.550 2043.510
[29] 2070.000 2054.000 2033.550 2017.680 2026.070 2039.220 2041.555
[36] 2010.730 2014.020 2015.620 2044.030 2056.745 2096.890 2151.620
[43] 2214.800 2225.330 2257.680 2253.714 2238.465 2256.090 2249.190
[50] 2266.000 2284.450 2287.845 2271.710 2258.570 2256.450 2278.210
[57] 2313.840 2304.270 2374.850 2402.280 2402.160 2384.500 2311.700
[64] 2351.410 2342.338 2390.000 2334.730 2283.000 2230.050 2242.720
[71] 2283.320 2295.000 2303.160 2263.520 2321.090 2342.370 2360.110
[78] 2402.990 2412.515 2402.000 2407.690 2404.880 2404.200 2382.830
[85] 2417.770 2441.073 2468.240 2487.330 2494.000 2498.290
boxplot.stats(dataset$adjOpen)$out
 [1] 2073.000 2068.890 2070.000 2105.910 2078.540 2094.210 2099.510
 [8] 2090.250 2104.360 2100.000 2110.390 2119.270 2067.000 2025.010
[15] 2041.830 2067.450 2050.520 2056.520 2076.190 2067.210 2023.370
[22] 2073.120 2101.130 2070.000 2071.760 2074.060 2085.000 2062.300
[29] 2078.990 2076.030 2061.000 2042.050 2041.840 2051.700 2065.370
[36] 2044.810 2038.860 2027.880 2057.630 2059.120 2097.950 2152.940
[43] 2222.500 2226.130 2277.960 2256.700 2266.250 2261.470 2275.160
[50] 2276.980 2303.000 2291.980 2307.890 2285.250 2293.230 2283.470
[57] 2319.930 2336.000 2407.145 2410.330 2404.490 2402.720 2369.740
[64] 2368.420 2350.640 2400.000 2374.890 2291.860 2261.710 2261.090
[71] 2291.830 2309.320 2336.906 2264.400 2328.040 2365.990 2367.000
[78] 2420.000 2412.835 2436.940 2421.960 2422.000 2435.310 2395.020
[85] 2422.520 2451.320 2479.900 2499.500 2494.010 2524.920
boxplot.stats(dataset$adjVolume)$out
 [1] 3402357 4449022 3530169 3841482 4269902 4745183 3654385 3017947
 [9] 2973891 2965771 3246573 3487056 3160585 3270248 3731589 2921393
[17] 3248393 4626086 3095263 5125791 3142760 4758496 3336352 3360727
[25] 3267883 3029471 3369275 4760260 3088305 3318204 4405584 2950120
[33] 4187586 3880723 3212657 4595891 3552194 6207027 5130576 2833483
[41] 4805752 3316905 3055216 3932954 2867053 2978300 3790618 3365365
[49] 4226748 3700125 4252365 3861489 4233435 3651106 3601750 4044137
[57] 3344450 4081528 3573755 3208495 2951309 3793630 3157875 4267698
[65] 3429036 3581072 3107763 3103882 2888827 4330862 3570927 4016353
[73] 4118170 2986439
#boxplots
boxplot(dataset$close)

boxplot(dataset$high)

boxplot(dataset$low)

boxplot(dataset$open)

boxplot(dataset$volume)

boxplot(dataset$adjClose)

boxplot(dataset$adjHigh)

boxplot(dataset$adjLow)

boxplot(dataset$adjOpen)

boxplot(dataset$adjVolume)

This scatter plot helps us to determine whether the closing price and volume are correlated to each other or not, it shows that the two attributes are corelated and have proportional relationship.

with(dataset, plot(volume, close))

The Bar plot represents the closing price and date in dataset. It indicates that closing prices at the end of a traded day are increasing or decreasing depending on the date.

barplot(height = dataset$close, names.arg = dataset$date, xlab = "Date", ylab = "Closing price", main = "date vs Close")

This Histogram represents the frequency of a stock closing price in the dataset. After observation, we noticed that the most values lie in between 1000 to 1200.

hist(dataset$close)

4. Data preprocessing

Here is our data set before preprocessing

#dataset before preprocessing
print(dataset)

Data cleaning, including handling missing values like NULLs, is crucial before utilizing data for analysis or modeling. It’s important to get the best quality of analysis. Such as accuracy where missing or incorrect data can skew analysis, leading to inaccurate insights or predictions. And clean data ensures the reliability of your findings, reducing the risk of making decisions based on flawed information.

to find the total null values in the dataset #Checking NULL, FALSE means no null, TRUE cells means the value of the cell is null

is.na(dataset)
         date close  high   low  open volume adjClose adjHigh
   [1,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
   [2,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
   [3,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
   [4,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
   [5,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
   [6,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
   [7,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
   [8,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
   [9,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [10,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [11,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [12,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [13,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [14,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [15,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [16,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [17,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [18,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [19,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [20,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [21,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [22,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [23,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [24,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [25,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [26,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [27,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [28,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [29,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [30,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [31,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [32,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [33,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [34,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [35,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [36,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [37,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [38,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [39,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [40,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [41,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [42,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [43,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [44,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [45,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [46,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [47,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [48,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [49,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [50,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [51,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [52,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [53,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [54,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [55,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [56,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [57,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [58,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [59,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [60,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [61,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [62,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [63,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [64,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [65,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [66,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [67,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [68,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [69,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [70,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [71,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [72,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [73,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [74,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [75,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [76,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [77,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [78,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [79,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [80,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [81,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [82,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [83,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [84,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [85,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [86,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [87,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [88,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [89,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
  [90,] FALSE FALSE FALSE FALSE FALSE  FALSE    FALSE   FALSE
        adjLow adjOpen adjVolume
   [1,]  FALSE   FALSE     FALSE
   [2,]  FALSE   FALSE     FALSE
   [3,]  FALSE   FALSE     FALSE
   [4,]  FALSE   FALSE     FALSE
   [5,]  FALSE   FALSE     FALSE
   [6,]  FALSE   FALSE     FALSE
   [7,]  FALSE   FALSE     FALSE
   [8,]  FALSE   FALSE     FALSE
   [9,]  FALSE   FALSE     FALSE
  [10,]  FALSE   FALSE     FALSE
  [11,]  FALSE   FALSE     FALSE
  [12,]  FALSE   FALSE     FALSE
  [13,]  FALSE   FALSE     FALSE
  [14,]  FALSE   FALSE     FALSE
  [15,]  FALSE   FALSE     FALSE
  [16,]  FALSE   FALSE     FALSE
  [17,]  FALSE   FALSE     FALSE
  [18,]  FALSE   FALSE     FALSE
  [19,]  FALSE   FALSE     FALSE
  [20,]  FALSE   FALSE     FALSE
  [21,]  FALSE   FALSE     FALSE
  [22,]  FALSE   FALSE     FALSE
  [23,]  FALSE   FALSE     FALSE
  [24,]  FALSE   FALSE     FALSE
  [25,]  FALSE   FALSE     FALSE
  [26,]  FALSE   FALSE     FALSE
  [27,]  FALSE   FALSE     FALSE
  [28,]  FALSE   FALSE     FALSE
  [29,]  FALSE   FALSE     FALSE
  [30,]  FALSE   FALSE     FALSE
  [31,]  FALSE   FALSE     FALSE
  [32,]  FALSE   FALSE     FALSE
  [33,]  FALSE   FALSE     FALSE
  [34,]  FALSE   FALSE     FALSE
  [35,]  FALSE   FALSE     FALSE
  [36,]  FALSE   FALSE     FALSE
  [37,]  FALSE   FALSE     FALSE
  [38,]  FALSE   FALSE     FALSE
  [39,]  FALSE   FALSE     FALSE
  [40,]  FALSE   FALSE     FALSE
  [41,]  FALSE   FALSE     FALSE
  [42,]  FALSE   FALSE     FALSE
  [43,]  FALSE   FALSE     FALSE
  [44,]  FALSE   FALSE     FALSE
  [45,]  FALSE   FALSE     FALSE
  [46,]  FALSE   FALSE     FALSE
  [47,]  FALSE   FALSE     FALSE
  [48,]  FALSE   FALSE     FALSE
  [49,]  FALSE   FALSE     FALSE
  [50,]  FALSE   FALSE     FALSE
  [51,]  FALSE   FALSE     FALSE
  [52,]  FALSE   FALSE     FALSE
  [53,]  FALSE   FALSE     FALSE
  [54,]  FALSE   FALSE     FALSE
  [55,]  FALSE   FALSE     FALSE
  [56,]  FALSE   FALSE     FALSE
  [57,]  FALSE   FALSE     FALSE
  [58,]  FALSE   FALSE     FALSE
  [59,]  FALSE   FALSE     FALSE
  [60,]  FALSE   FALSE     FALSE
  [61,]  FALSE   FALSE     FALSE
  [62,]  FALSE   FALSE     FALSE
  [63,]  FALSE   FALSE     FALSE
  [64,]  FALSE   FALSE     FALSE
  [65,]  FALSE   FALSE     FALSE
  [66,]  FALSE   FALSE     FALSE
  [67,]  FALSE   FALSE     FALSE
  [68,]  FALSE   FALSE     FALSE
  [69,]  FALSE   FALSE     FALSE
  [70,]  FALSE   FALSE     FALSE
  [71,]  FALSE   FALSE     FALSE
  [72,]  FALSE   FALSE     FALSE
  [73,]  FALSE   FALSE     FALSE
  [74,]  FALSE   FALSE     FALSE
  [75,]  FALSE   FALSE     FALSE
  [76,]  FALSE   FALSE     FALSE
  [77,]  FALSE   FALSE     FALSE
  [78,]  FALSE   FALSE     FALSE
  [79,]  FALSE   FALSE     FALSE
  [80,]  FALSE   FALSE     FALSE
  [81,]  FALSE   FALSE     FALSE
  [82,]  FALSE   FALSE     FALSE
  [83,]  FALSE   FALSE     FALSE
  [84,]  FALSE   FALSE     FALSE
  [85,]  FALSE   FALSE     FALSE
  [86,]  FALSE   FALSE     FALSE
  [87,]  FALSE   FALSE     FALSE
  [88,]  FALSE   FALSE     FALSE
  [89,]  FALSE   FALSE     FALSE
  [90,]  FALSE   FALSE     FALSE
 [ reached getOption("max.print") -- omitted 1168 rows ]
sum(is.na(dataset))
[1] 0
print("Since there is no NULL values we don't need to remove any rows")
[1] "Since there is no NULL values we don't need to remove any rows"

In our data since there are no Null values, we don’t need to remove any rows.

Since most attributes in our dataset are numeric and removing outliers will affect our calculations and prediction, we will remove closing price and volumes outliers only.

#dataset before removing outliers
print(dataset)
summary(dataset)
      date                close             high       
 Min.   :2016-06-14   Min.   : 668.3   Min.   : 672.3  
 1st Qu.:2017-09-12   1st Qu.: 960.8   1st Qu.: 968.8  
 Median :2018-12-11   Median :1132.5   Median :1143.9  
 Mean   :2018-12-12   Mean   :1216.3   Mean   :1227.4  
 3rd Qu.:2020-03-12   3rd Qu.:1360.6   3rd Qu.:1374.3  
 Max.   :2021-06-11   Max.   :2521.6   Max.   :2527.0  
      low              open          volume           adjClose     
 Min.   : 663.3   Min.   : 671   Min.   : 346753   Min.   : 668.3  
 1st Qu.: 952.2   1st Qu.: 959   1st Qu.:1173522   1st Qu.: 960.8  
 Median :1117.9   Median :1131   Median :1412588   Median :1132.5  
 Mean   :1204.2   Mean   :1215   Mean   :1601590   Mean   :1216.3  
 3rd Qu.:1348.6   3rd Qu.:1361   3rd Qu.:1812156   3rd Qu.:1360.6  
 Max.   :2498.3   Max.   :2525   Max.   :6207027   Max.   :2521.6  
    adjHigh           adjLow          adjOpen       adjVolume      
 Min.   : 672.3   Min.   : 663.3   Min.   : 671   Min.   : 346753  
 1st Qu.: 968.8   1st Qu.: 952.2   1st Qu.: 959   1st Qu.:1173522  
 Median :1143.9   Median :1117.9   Median :1131   Median :1412588  
 Mean   :1227.4   Mean   :1204.2   Mean   :1215   Mean   :1601590  
 3rd Qu.:1374.3   3rd Qu.:1348.6   3rd Qu.:1361   3rd Qu.:1812156  
 Max.   :2527.0   Max.   :2498.3   Max.   :2525   Max.   :6207027  
str(dataset)
'data.frame':   1258 obs. of  11 variables:
 $ date     : Date, format: "2016-06-14" ...
 $ close    : num  718 719 710 692 694 ...
 $ high     : num  722 723 717 709 702 ...
 $ low      : num  713 717 703 688 693 ...
 $ open     : num  716 719 715 709 699 ...
 $ volume   : int  1306065 1214517 1982471 3402357 2082538 1465634 1184318 2171415 4449022 2641085 ...
 $ adjClose : num  718 719 710 692 694 ...
 $ adjHigh  : num  722 723 717 709 702 ...
 $ adjLow   : num  713 717 703 688 693 ...
 $ adjOpen  : num  716 719 715 709 699 ...
 $ adjVolume: int  1306065 1214517 1982471 3402357 2082538 1465634 1184318 2171415 4449022 2641085 ...
#removing close outlier
outliers <- boxplot(dataset$close, plot=FALSE)$out
dataset <- dataset[-which(dataset$close %in% outliers),]
boxplot.stats(dataset$close)$out
 [1] 1749.13 1763.37 1761.75 1763.00 1752.71 1749.84 1777.02 1781.38
 [9] 1770.15 1746.78 1763.92 1768.88 1771.43 1793.19 1760.74 1798.10
[17] 1827.95 1826.77 1827.99 1819.48 1818.55 1784.13 1775.33 1781.77
[25] 1760.06 1767.77 1763.00 1747.90 1776.09 1758.72 1751.88 1787.25
[33] 1807.21 1766.72 1746.55 1754.40 1790.86 1886.90 1891.25 1901.05
[41] 1899.40 1917.24 1830.79 1863.11 1835.74 1901.35 1927.51
#removing volume's outlier
outliers <- boxplot(dataset$volume, plot=FALSE)$out
dataset <- dataset[-which(dataset$volume %in% outliers),]
boxplot.stats(dataset$volume)$out
 [1] 2641085 2700470 2749221 2607121 2553771 2712222 2634669 2720942
 [9] 2560277 2580374 2558385 2726830 2680400 2619234 2675742 2580612
[17] 2769225 2673464 2576470 2642983 2597455 2561288 2660628 2611373
[25] 2611229 2574061 2664723 2668906 2608568 2610884 2568345 2636142
[33] 2602114 2748292
#data set after removing outliers
print(dataset)
summary(dataset)
      date                close             high       
 Min.   :2016-06-14   Min.   : 668.3   Min.   : 672.3  
 1st Qu.:2017-08-10   1st Qu.: 942.2   1st Qu.: 943.8  
 Median :2018-09-29   Median :1115.7   Median :1125.6  
 Mean   :2018-10-03   Mean   :1139.9   Mean   :1149.5  
 3rd Qu.:2019-11-14   3rd Qu.:1264.7   3rd Qu.:1275.7  
 Max.   :2021-02-02   Max.   :1927.5   Max.   :1955.8  
      low              open            volume       
 Min.   : 663.3   Min.   : 671.0   Min.   : 346753  
 1st Qu.: 933.8   1st Qu.: 939.7   1st Qu.:1167344  
 Median :1104.2   Median :1115.8   Median :1394116  
 Mean   :1129.1   Mean   :1138.6   Mean   :1480717  
 3rd Qu.:1251.1   3rd Qu.:1262.0   3rd Qu.:1719968  
 Max.   :1914.5   Max.   :1922.6   Max.   :2769225  
    adjClose         adjHigh           adjLow      
 Min.   : 668.3   Min.   : 672.3   Min.   : 663.3  
 1st Qu.: 942.2   1st Qu.: 943.8   1st Qu.: 933.8  
 Median :1115.7   Median :1125.6   Median :1104.2  
 Mean   :1139.9   Mean   :1149.5   Mean   :1129.1  
 3rd Qu.:1264.7   3rd Qu.:1275.7   3rd Qu.:1251.1  
 Max.   :1927.5   Max.   :1955.8   Max.   :1914.5  
    adjOpen         adjVolume      
 Min.   : 671.0   Min.   : 346753  
 1st Qu.: 939.7   1st Qu.:1167344  
 Median :1115.8   Median :1394116  
 Mean   :1138.6   Mean   :1480717  
 3rd Qu.:1262.0   3rd Qu.:1719968  
 Max.   :1922.6   Max.   :2769225  
str(dataset)
'data.frame':   1096 obs. of  11 variables:
 $ date     : Date, format: "2016-06-14" ...
 $ close    : num  718 719 710 694 696 ...
 $ high     : num  722 723 717 702 703 ...
 $ low      : num  713 717 703 693 692 ...
 $ open     : num  716 719 715 699 698 ...
 $ volume   : int  1306065 1214517 1982471 2082538 1465634 1184318 2171415 2641085 2173762 1932561 ...
 $ adjClose : num  718 719 710 694 696 ...
 $ adjHigh  : num  722 723 717 702 703 ...
 $ adjLow   : num  713 717 703 693 692 ...
 $ adjOpen  : num  716 719 715 699 698 ...
 $ adjVolume: int  1306065 1214517 1982471 2082538 1465634 1184318 2171415 2641085 2173762 1932561 ...

Feature selection

Remove Redundant Features

# load the library        
library(mlbench)
Warning: package ‘mlbench’ was built under R version 4.3.2
library(caret)
library(ggplot2)
library(lattice)

# calculate correlation matrix
correlationMatrix <- cor(dataset[,2:11])

# summarize the correlation matrix
print(correlationMatrix)
              close      high       low      open    volume
close     1.0000000 0.9993759 0.9994124 0.9986066 0.1155092
high      0.9993759 1.0000000 0.9992333 0.9993994 0.1278230
low       0.9994124 0.9992333 1.0000000 0.9993082 0.1038372
open      0.9986066 0.9993994 0.9993082 1.0000000 0.1177215
volume    0.1155092 0.1278230 0.1038372 0.1177215 1.0000000
adjClose  1.0000000 0.9993759 0.9994124 0.9986066 0.1155092
adjHigh   0.9993759 1.0000000 0.9992333 0.9993994 0.1278230
adjLow    0.9994124 0.9992333 1.0000000 0.9993082 0.1038372
adjOpen   0.9986066 0.9993994 0.9993082 1.0000000 0.1177215
adjVolume 0.1155092 0.1278230 0.1038372 0.1177215 1.0000000
           adjClose   adjHigh    adjLow   adjOpen adjVolume
close     1.0000000 0.9993759 0.9994124 0.9986066 0.1155092
high      0.9993759 1.0000000 0.9992333 0.9993994 0.1278230
low       0.9994124 0.9992333 1.0000000 0.9993082 0.1038372
open      0.9986066 0.9993994 0.9993082 1.0000000 0.1177215
volume    0.1155092 0.1278230 0.1038372 0.1177215 1.0000000
adjClose  1.0000000 0.9993759 0.9994124 0.9986066 0.1155092
adjHigh   0.9993759 1.0000000 0.9992333 0.9993994 0.1278230
adjLow    0.9994124 0.9992333 1.0000000 0.9993082 0.1038372
adjOpen   0.9986066 0.9993994 0.9993082 1.0000000 0.1177215
adjVolume 0.1155092 0.1278230 0.1038372 0.1177215 1.0000000
# find attributes that are highly corrected (ideally >0.75)
highlyCorrelated <- findCorrelation(correlationMatrix, cutoff=0.5 )

# print indexes of highly correlated attributes
print(highlyCorrelated)
[1] 7 2 4 9 1 6 8 5

dataset before normalization

#dataset before normalization 
print(dataset)
summary(dataset)
      date                close             high       
 Min.   :2016-06-14   Min.   : 668.3   Min.   : 672.3  
 1st Qu.:2017-08-10   1st Qu.: 942.2   1st Qu.: 943.8  
 Median :2018-09-29   Median :1115.7   Median :1125.6  
 Mean   :2018-10-03   Mean   :1139.9   Mean   :1149.5  
 3rd Qu.:2019-11-14   3rd Qu.:1264.7   3rd Qu.:1275.7  
 Max.   :2021-02-02   Max.   :1927.5   Max.   :1955.8  
      low              open            volume       
 Min.   : 663.3   Min.   : 671.0   Min.   : 346753  
 1st Qu.: 933.8   1st Qu.: 939.7   1st Qu.:1167344  
 Median :1104.2   Median :1115.8   Median :1394116  
 Mean   :1129.1   Mean   :1138.6   Mean   :1480717  
 3rd Qu.:1251.1   3rd Qu.:1262.0   3rd Qu.:1719968  
 Max.   :1914.5   Max.   :1922.6   Max.   :2769225  
    adjClose         adjHigh           adjLow      
 Min.   : 668.3   Min.   : 672.3   Min.   : 663.3  
 1st Qu.: 942.2   1st Qu.: 943.8   1st Qu.: 933.8  
 Median :1115.7   Median :1125.6   Median :1104.2  
 Mean   :1139.9   Mean   :1149.5   Mean   :1129.1  
 3rd Qu.:1264.7   3rd Qu.:1275.7   3rd Qu.:1251.1  
 Max.   :1927.5   Max.   :1955.8   Max.   :1914.5  
    adjOpen         adjVolume      
 Min.   : 671.0   Min.   : 346753  
 1st Qu.: 939.7   1st Qu.:1167344  
 Median :1115.8   Median :1394116  
 Mean   :1138.6   Mean   :1480717  
 3rd Qu.:1262.0   3rd Qu.:1719968  
 Max.   :1922.6   Max.   :2769225  
str(dataset)
'data.frame':   1096 obs. of  11 variables:
 $ date     : Date, format: "2016-06-14" ...
 $ close    : num  718 719 710 694 696 ...
 $ high     : num  722 723 717 702 703 ...
 $ low      : num  713 717 703 693 692 ...
 $ open     : num  716 719 715 699 698 ...
 $ volume   : int  1306065 1214517 1982471 2082538 1465634 1184318 2171415 2641085 2173762 1932561 ...
 $ adjClose : num  718 719 710 694 696 ...
 $ adjHigh  : num  722 723 717 702 703 ...
 $ adjLow   : num  713 717 703 693 692 ...
 $ adjOpen  : num  716 719 715 699 698 ...
 $ adjVolume: int  1306065 1214517 1982471 2082538 1465634 1184318 2171415 2641085 2173762 1932561 ...

normalization was performed to ensure consistent scaling of the data. The normalization technique applied was the max-min normalization. This technique rescales the values of specific attributes within a defined range between 0 and 1.

We can use the normalized dataset provides a more uniform and comparable representation of the attributes, enabling accurate analysis and modeling for stock predaction with result as shown.

normalize <- function(x) {return ((x - min(x)) / (max(x) - min(x)))}
dataWithoutNormalization <- dataset
dataset$close<-normalize(dataWithoutNormalization$close)
dataset$volume<-normalize(dataWithoutNormalization$volume)
dataset$open<-normalize(dataWithoutNormalization$open)
dataset$low <-normalize(dataWithoutNormalization$low)
dataset$high <-normalize(dataWithoutNormalization$high)

dataset after normalization

#dataset after normalization 
print(dataset)
summary(dataset)
      date                close             high       
 Min.   :2016-06-14   Min.   :0.0000   Min.   :0.0000  
 1st Qu.:2017-08-10   1st Qu.:0.2175   1st Qu.:0.2115  
 Median :2018-09-29   Median :0.3553   Median :0.3532  
 Mean   :2018-10-03   Mean   :0.3746   Mean   :0.3718  
 3rd Qu.:2019-11-14   3rd Qu.:0.4736   3rd Qu.:0.4701  
 Max.   :2021-02-02   Max.   :1.0000   Max.   :1.0000  
      low              open            volume      
 Min.   :0.0000   Min.   :0.0000   Min.   :0.0000  
 1st Qu.:0.2162   1st Qu.:0.2147   1st Qu.:0.3387  
 Median :0.3524   Median :0.3554   Median :0.4324  
 Mean   :0.3723   Mean   :0.3736   Mean   :0.4681  
 3rd Qu.:0.4698   3rd Qu.:0.4722   3rd Qu.:0.5669  
 Max.   :1.0000   Max.   :1.0000   Max.   :1.0000  
    adjClose         adjHigh           adjLow      
 Min.   : 668.3   Min.   : 672.3   Min.   : 663.3  
 1st Qu.: 942.2   1st Qu.: 943.8   1st Qu.: 933.8  
 Median :1115.7   Median :1125.6   Median :1104.2  
 Mean   :1139.9   Mean   :1149.5   Mean   :1129.1  
 3rd Qu.:1264.7   3rd Qu.:1275.7   3rd Qu.:1251.1  
 Max.   :1927.5   Max.   :1955.8   Max.   :1914.5  
    adjOpen         adjVolume      
 Min.   : 671.0   Min.   : 346753  
 1st Qu.: 939.7   1st Qu.:1167344  
 Median :1115.8   Median :1394116  
 Mean   :1138.6   Mean   :1480717  
 3rd Qu.:1262.0   3rd Qu.:1719968  
 Max.   :1922.6   Max.   :2769225  
str(dataset)
'data.frame':   1096 obs. of  11 variables:
 $ date     : Date, format: "2016-06-14" ...
 $ close    : num  0.0397 0.0402 0.0334 0.0202 0.022 ...
 $ high     : num  0.0391 0.0395 0.0346 0.0235 0.0237 ...
 $ low      : num  0.0398 0.0432 0.0319 0.0241 0.023 ...
 $ open     : num  0.0363 0.0384 0.0351 0.0222 0.0219 ...
 $ volume   : num  0.396 0.358 0.675 0.717 0.462 ...
 $ adjClose : num  718 719 710 694 696 ...
 $ adjHigh  : num  722 723 717 702 703 ...
 $ adjLow   : num  713 717 703 693 692 ...
 $ adjOpen  : num  716 719 715 699 698 ...
 $ adjVolume: int  1306065 1214517 1982471 2082538 1465634 1184318 2171415 2641085 2173762 1932561 ...

dataset before Discretization

#dataset before Discretization 
print(dataset)
summary(dataset)
      date                close             high       
 Min.   :2016-06-14   Min.   :0.0000   Min.   :0.0000  
 1st Qu.:2017-08-10   1st Qu.:0.2175   1st Qu.:0.2115  
 Median :2018-09-29   Median :0.3553   Median :0.3532  
 Mean   :2018-10-03   Mean   :0.3746   Mean   :0.3718  
 3rd Qu.:2019-11-14   3rd Qu.:0.4736   3rd Qu.:0.4701  
 Max.   :2021-02-02   Max.   :1.0000   Max.   :1.0000  
      low              open            volume      
 Min.   :0.0000   Min.   :0.0000   Min.   :0.0000  
 1st Qu.:0.2162   1st Qu.:0.2147   1st Qu.:0.3387  
 Median :0.3524   Median :0.3554   Median :0.4324  
 Mean   :0.3723   Mean   :0.3736   Mean   :0.4681  
 3rd Qu.:0.4698   3rd Qu.:0.4722   3rd Qu.:0.5669  
 Max.   :1.0000   Max.   :1.0000   Max.   :1.0000  
    adjClose         adjHigh           adjLow      
 Min.   : 668.3   Min.   : 672.3   Min.   : 663.3  
 1st Qu.: 942.2   1st Qu.: 943.8   1st Qu.: 933.8  
 Median :1115.7   Median :1125.6   Median :1104.2  
 Mean   :1139.9   Mean   :1149.5   Mean   :1129.1  
 3rd Qu.:1264.7   3rd Qu.:1275.7   3rd Qu.:1251.1  
 Max.   :1927.5   Max.   :1955.8   Max.   :1914.5  
    adjOpen         adjVolume      
 Min.   : 671.0   Min.   : 346753  
 1st Qu.: 939.7   1st Qu.:1167344  
 Median :1115.8   Median :1394116  
 Mean   :1138.6   Mean   :1480717  
 3rd Qu.:1262.0   3rd Qu.:1719968  
 Max.   :1922.6   Max.   :2769225  
str(dataset)
'data.frame':   1096 obs. of  11 variables:
 $ date     : Date, format: "2016-06-14" ...
 $ close    : num  0.0397 0.0402 0.0334 0.0202 0.022 ...
 $ high     : num  0.0391 0.0395 0.0346 0.0235 0.0237 ...
 $ low      : num  0.0398 0.0432 0.0319 0.0241 0.023 ...
 $ open     : num  0.0363 0.0384 0.0351 0.0222 0.0219 ...
 $ volume   : num  0.396 0.358 0.675 0.717 0.462 ...
 $ adjClose : num  718 719 710 694 696 ...
 $ adjHigh  : num  722 723 717 702 703 ...
 $ adjLow   : num  713 717 703 693 692 ...
 $ adjOpen  : num  716 719 715 699 698 ...
 $ adjVolume: int  1306065 1214517 1982471 2082538 1465634 1184318 2171415 2641085 2173762 1932561 ...

we used the Discretization technique on our class label “close” to simplify it as it has a large continuous values, we made them fall into intervals, to make it easier to analyze

and we chose the value 0.2957251 as it the mean value for the closing

dataset$close <- ifelse(dataset$close <= 0.2957251 , "low","High")
print(dataset)

we discretized it into two categories (low, high) based on the maen, low meaning it is less than the mean of the close , and high meaning it is equal to or higher than the mean.

Encoding We encoded close data into factors, which would help the model read this data easily


dataset$close <- factor(dataset$close,levels = c("low", "High"), labels = c("1", "2"))

print(dataset)

dataset after Discretization

#dataset after Discretization 
print(dataset)
summary(dataset)
      date            close        high             low        
 Min.   :2016-06-14   1:396   Min.   :0.0000   Min.   :0.0000  
 1st Qu.:2017-08-10   2:700   1st Qu.:0.2115   1st Qu.:0.2162  
 Median :2018-09-29           Median :0.3532   Median :0.3524  
 Mean   :2018-10-03           Mean   :0.3718   Mean   :0.3723  
 3rd Qu.:2019-11-14           3rd Qu.:0.4701   3rd Qu.:0.4698  
 Max.   :2021-02-02           Max.   :1.0000   Max.   :1.0000  
      open            volume          adjClose     
 Min.   :0.0000   Min.   :0.0000   Min.   : 668.3  
 1st Qu.:0.2147   1st Qu.:0.3387   1st Qu.: 942.2  
 Median :0.3554   Median :0.4324   Median :1115.7  
 Mean   :0.3736   Mean   :0.4681   Mean   :1139.9  
 3rd Qu.:0.4722   3rd Qu.:0.5669   3rd Qu.:1264.7  
 Max.   :1.0000   Max.   :1.0000   Max.   :1927.5  
    adjHigh           adjLow          adjOpen      
 Min.   : 672.3   Min.   : 663.3   Min.   : 671.0  
 1st Qu.: 943.8   1st Qu.: 933.8   1st Qu.: 939.7  
 Median :1125.6   Median :1104.2   Median :1115.8  
 Mean   :1149.5   Mean   :1129.1   Mean   :1138.6  
 3rd Qu.:1275.7   3rd Qu.:1251.1   3rd Qu.:1262.0  
 Max.   :1955.8   Max.   :1914.5   Max.   :1922.6  
   adjVolume      
 Min.   : 346753  
 1st Qu.:1167344  
 Median :1394116  
 Mean   :1480717  
 3rd Qu.:1719968  
 Max.   :2769225  
str(dataset)
'data.frame':   1096 obs. of  11 variables:
 $ date     : Date, format: "2016-06-14" ...
 $ close    : Factor w/ 2 levels "1","2": 1 1 1 1 1 1 1 1 1 1 ...
 $ high     : num  0.0391 0.0395 0.0346 0.0235 0.0237 ...
 $ low      : num  0.0398 0.0432 0.0319 0.0241 0.023 ...
 $ open     : num  0.0363 0.0384 0.0351 0.0222 0.0219 ...
 $ volume   : num  0.396 0.358 0.675 0.717 0.462 ...
 $ adjClose : num  718 719 710 694 696 ...
 $ adjHigh  : num  722 723 717 702 703 ...
 $ adjLow   : num  713 717 703 693 692 ...
 $ adjOpen  : num  716 719 715 699 698 ...
 $ adjVolume: int  1306065 1214517 1982471 2082538 1465634 1184318 2171415 2641085 2173762 1932561 ...

summary after preprocessing after preprocessing the data for stock price prediction, several steps are taken to refine, clean, and prepare the data for analysis and modeling. These preprocessing steps aim to enhance the quality and reliability of the data for more accurate stock price prediction.

dataset after preprocessing

#dataset after preprocessing 
print(dataset)
summary(dataset)
      date            close        high             low        
 Min.   :2016-06-14   1:396   Min.   :0.0000   Min.   :0.0000  
 1st Qu.:2017-08-10   2:700   1st Qu.:0.2115   1st Qu.:0.2162  
 Median :2018-09-29           Median :0.3532   Median :0.3524  
 Mean   :2018-10-03           Mean   :0.3718   Mean   :0.3723  
 3rd Qu.:2019-11-14           3rd Qu.:0.4701   3rd Qu.:0.4698  
 Max.   :2021-02-02           Max.   :1.0000   Max.   :1.0000  
      open            volume          adjClose     
 Min.   :0.0000   Min.   :0.0000   Min.   : 668.3  
 1st Qu.:0.2147   1st Qu.:0.3387   1st Qu.: 942.2  
 Median :0.3554   Median :0.4324   Median :1115.7  
 Mean   :0.3736   Mean   :0.4681   Mean   :1139.9  
 3rd Qu.:0.4722   3rd Qu.:0.5669   3rd Qu.:1264.7  
 Max.   :1.0000   Max.   :1.0000   Max.   :1927.5  
    adjHigh           adjLow          adjOpen      
 Min.   : 672.3   Min.   : 663.3   Min.   : 671.0  
 1st Qu.: 943.8   1st Qu.: 933.8   1st Qu.: 939.7  
 Median :1125.6   Median :1104.2   Median :1115.8  
 Mean   :1149.5   Mean   :1129.1   Mean   :1138.6  
 3rd Qu.:1275.7   3rd Qu.:1251.1   3rd Qu.:1262.0  
 Max.   :1955.8   Max.   :1914.5   Max.   :1922.6  
   adjVolume      
 Min.   : 346753  
 1st Qu.:1167344  
 Median :1394116  
 Mean   :1480717  
 3rd Qu.:1719968  
 Max.   :2769225  
str(dataset)
'data.frame':   1096 obs. of  11 variables:
 $ date     : Date, format: "2016-06-14" ...
 $ close    : Factor w/ 2 levels "1","2": 1 1 1 1 1 1 1 1 1 1 ...
 $ high     : num  0.0391 0.0395 0.0346 0.0235 0.0237 ...
 $ low      : num  0.0398 0.0432 0.0319 0.0241 0.023 ...
 $ open     : num  0.0363 0.0384 0.0351 0.0222 0.0219 ...
 $ volume   : num  0.396 0.358 0.675 0.717 0.462 ...
 $ adjClose : num  718 719 710 694 696 ...
 $ adjHigh  : num  722 723 717 702 703 ...
 $ adjLow   : num  713 717 703 693 692 ...
 $ adjOpen  : num  716 719 715 699 698 ...
 $ adjVolume: int  1306065 1214517 1982471 2082538 1465634 1184318 2171415 2641085 2173762 1932561 ...

Feature selection

Feature selection is a process of selecting a subset of relevant features (or attributes) from the original set of features in a dataset. The goal of feature selection is to choose the most relevant and important features, thereby reducing dimensionality, and improving model performance.

#Feature selection ,Feature selection using Recursive Feature Elimination or RFE

    library(mlbench)
library(caret)

# define the control using a random forest selection function 
# number=12 means the length of the list
control <- rfeControl(functions=rfFuncs, method="cv", number=11)
# run the RFE algorithm from column 1 to 11  
results <- rfe(dataset[,1:10],dataset[,11], sizes=c(1:10), rfeControl=control)

summarize the results

print(results)

Recursive feature selection

Outer resampling method: Cross-Validated (11 fold) 

Resampling performance over subset size:

The top 1 variables (out of 1):
   volume

list the chosen features

predictors(results)
[1] "volume"

plot the results

plot(results, type=c("h", "o"))

5. Data Mining Techniques

We did both supervised and unsupervised learning techniques on our dataset (Google stock prediction), which involves classification and clustering methods, for classification we did a partitioning method called the train-test split, which splits the dataset into two subsets of different ratios, and we implemented three algorithms to form 9 different decision trees.

6. Evaluation and Comparison

We will choose the attributes with the highest importance (from feature selection) to create a tree:

  1. Dividing the dataset:

we divided our dataset into two divisions for each split:

first one 70-30, which means Training(70%) and Testing(30%):

# a fixed random seed to make results reproducible
set.seed(1234)

# 1.Split the datasets into two subsets: Training(70%) and Testing(30%):
ind1 <- sample(2, nrow(dataset), replace=TRUE, prob=c( 0.70, 0.30))
trainData  <- dataset[ind1==1,]
testData <- dataset[ind1==2,]
  1. Determine the predictor attributes and the class label attribute.( the formula):
library(party)    
Loading required package: grid
Loading required package: mvtnorm
Loading required package: modeltools
Loading required package: stats4
Loading required package: strucchange
Loading required package: zoo

Attaching package: ‘zoo’

The following objects are masked from ‘package:base’:

    as.Date, as.Date.numeric

Loading required package: sandwich
#myFormula 
myFormula <- close ~volume+open+high+low
  1. Build a decision tree using Information gain:

Information gain is a concept used in the field of machine learning and decision tree algorithms. It is a measure of the effectiveness of a particular attribute in classifying data. In the context of decision trees, information gain helps determine the order in which attributes are chosen for splitting the data.

dataset_ctree <- ctree(myFormula, data=trainData)
table(predict(dataset_ctree), trainData$close)
   
      1   2
  1 284  11
  2   0 476
# 4.Print and plot the tree:

print(dataset_ctree)

     Conditional inference tree with 4 terminal nodes

Response:  close 
Inputs:  volume, open, high, low 
Number of observations:  771 

1) open <= 0.2974608; criterion = 1, statistic = 423.273
  2) high <= 0.2892353; criterion = 1, statistic = 19.817
    3)*  weights = 267 
  2) high > 0.2892353
    4)*  weights = 17 
1) open > 0.2974608
  5) low <= 0.2955676; criterion = 0.995, statistic = 10.36
    6)*  weights = 11 
  5) low > 0.2955676
    7)*  weights = 476 
plot(dataset_ctree, type="simple")

# 5.Use the constructed model to predict the class labels of test data:
testPred <- predict(dataset_ctree, newdata = testData)
result<-table(testPred, testData$close)
result
        
testPred   1   2
       1 111   3
       2   1 210
# Evaluate the model and create confusion matrix
install.packages("caret")
Error in install.packages : Updating loaded packages
install.packages('e1071', dependencies=TRUE)
WARNING: Rtools is required to build R packages but is not currently installed. Please download and install the appropriate version of Rtools before proceeding:

https://cran.rstudio.com/bin/windows/Rtools/
trying URL 'https://cran.rstudio.com/bin/windows/contrib/4.3/e1071_1.7-13.zip'
Content type 'application/zip' length 653332 bytes (638 KB)
downloaded 638 KB
package ‘e1071’ successfully unpacked and MD5 sums checked

The downloaded binary packages are in
    C:\Users\shade\AppData\Local\Temp\RtmpIFXKiG\downloaded_packages
library(e1071)
Warning: package ‘e1071’ was built under R version 4.3.2
library(caret)

co_result <- confusionMatrix(result)

print(co_result)
Confusion Matrix and Statistics

        
testPred   1   2
       1 111   3
       2   1 210
                                          
               Accuracy : 0.9877          
                 95% CI : (0.9688, 0.9966)
    No Information Rate : 0.6554          
    P-Value [Acc > NIR] : <2e-16          
                                          
                  Kappa : 0.9729          
                                          
 Mcnemar's Test P-Value : 0.6171          
                                          
            Sensitivity : 0.9911          
            Specificity : 0.9859          
         Pos Pred Value : 0.9737          
         Neg Pred Value : 0.9953          
             Prevalence : 0.3446          
         Detection Rate : 0.3415          
   Detection Prevalence : 0.3508          
      Balanced Accuracy : 0.9885          
                                          
       'Positive' Class : 1               
                                          
sensitivity(as.table(co_result))
[1] 0.9910714
specificity(as.table(co_result))
[1] 0.9859155
precision(as.table(co_result))
[1] 0.9736842
acc <- co_result$overall["Accuracy"]
acc
 Accuracy 
0.9876923 
  1. Building the Tree using Gini Index(CART)

The Gini Index is another criterion used in decision tree algorithms, particularly in the context of the Classification and Regression Trees (CART) algorithm. Like information gain, the Gini Index is used to evaluate the impurity or homogeneity of a dataset.

The Gini Index for a specific attribute measures the probability of incorrectly classifying a randomly chosen element in the dataset. A lower Gini Index indicates a purer or more homogeneous set. In the context of decision trees, the attribute with the lowest Gini Index is chosen as the split attribute.

# For decision tree model
install.packages("rpart")
Error in install.packages : Updating loaded packages
library(rpart)
# For data visualization
library(rpart.plot)
Warning: package ‘rpart.plot’ was built under R version 4.3.2
dataset.cart <- rpart(myFormula, data = trainData, method = "class", parms = list(split = "gini"))

Visualizing the unpruned tree

library(rpart.plot)
rpart.plot(dataset.cart)

Checking the order of variable importance

dataset.cart$variable.importance
       low       high       open     volume 
343.117705 330.102896 326.553402   4.732658 
pred.tree = predict(dataset.cart, testData, type = "class")

table(pred.tree,testData$close)
         
pred.tree   1   2
        1 111   3
        2   1 210
# 5.Use the constructed model to predict the class labels of test data:
testPred <- predict(dataset_ctree, newdata = testData)
result<-table(testPred, testData$close)
result
        
testPred   1   2
       1 111   3
       2   1 210
# Evaluate the model and create confusion matrix
install.packages("caret")
Error in install.packages : Updating loaded packages
install.packages('e1071', dependencies=TRUE)
Error in install.packages : Updating loaded packages
library(e1071)
library(caret)

co_result <- confusionMatrix(result)

print(co_result)
Confusion Matrix and Statistics

        
testPred   1   2
       1 111   3
       2   1 210
                                          
               Accuracy : 0.9877          
                 95% CI : (0.9688, 0.9966)
    No Information Rate : 0.6554          
    P-Value [Acc > NIR] : <2e-16          
                                          
                  Kappa : 0.9729          
                                          
 Mcnemar's Test P-Value : 0.6171          
                                          
            Sensitivity : 0.9911          
            Specificity : 0.9859          
         Pos Pred Value : 0.9737          
         Neg Pred Value : 0.9953          
             Prevalence : 0.3446          
         Detection Rate : 0.3415          
   Detection Prevalence : 0.3508          
      Balanced Accuracy : 0.9885          
                                          
       'Positive' Class : 1               
                                          
sensitivity(as.table(co_result))
[1] 0.9910714
specificity(as.table(co_result))
[1] 0.9859155
precision(as.table(co_result))
[1] 0.9736842
acc <- co_result$overall["Accuracy"]
acc
 Accuracy 
0.9876923 
  1. Building the Tree using Gain ratio(C5)

The Gain Ratio is used to select the attribute that maximizes the Information Gain while avoiding the bias towards attributes with many values. It provides a more balanced measure for attribute selection in decision tree construction.

While Information Gain simply measures the reduction in entropy or uncertainty, Gain Ratio takes into account the intrinsic information of an attribute. It aims to penalize attributes that may have a large number of values, potentially leading to overfitting.

install.packages("caret")
Error in install.packages : Updating loaded packages
install.packages("C50")
WARNING: Rtools is required to build R packages but is not currently installed. Please download and install the appropriate version of Rtools before proceeding:

https://cran.rstudio.com/bin/windows/Rtools/
trying URL 'https://cran.rstudio.com/bin/windows/contrib/4.3/C50_0.1.8.zip'
Content type 'application/zip' length 342652 bytes (334 KB)
downloaded 334 KB
package ‘C50’ successfully unpacked and MD5 sums checked

The downloaded binary packages are in
    C:\Users\shade\AppData\Local\Temp\RtmpIFXKiG\downloaded_packages
install.packages("printr")
WARNING: Rtools is required to build R packages but is not currently installed. Please download and install the appropriate version of Rtools before proceeding:

https://cran.rstudio.com/bin/windows/Rtools/
trying URL 'https://cran.rstudio.com/bin/windows/contrib/4.3/printr_0.3.zip'
Content type 'application/zip' length 39419 bytes (38 KB)
downloaded 38 KB
package ‘printr’ successfully unpacked and MD5 sums checked

The downloaded binary packages are in
    C:\Users\shade\AppData\Local\Temp\RtmpIFXKiG\downloaded_packages
library(C50)
Warning: package ‘C50’ was built under R version 4.3.2
library(printr)
Warning: package ‘printr’ was built under R version 4.3.2Registered S3 method overwritten by 'printr':
  method                from     
  knit_print.data.frame rmarkdown
library(caret)
#train using the trainData and create the c5.0 gain ratio tree
CloseTree <- C5.0(myFormula, data=trainData)
summary(CloseTree)

Call:
C5.0.formula(formula = myFormula, data = trainData)


C5.0 [Release 2.07 GPL Edition]     Fri Dec  1 06:15:18 2023
-------------------------------

Class specified by attribute `outcome'

Read 771 cases (5 attributes) from undefined.data

Decision tree:

low > 0.2960392: 2 (481/1)
low <= 0.2960392:
:...high <= 0.2892354: 1 (266)
    high > 0.2892354:
    :...high > 0.3075281: 2 (2)
        high <= 0.3075281:
        :...open <= 0.278852: 2 (2)
            open > 0.278852: 1 (20/3)


Evaluation on training data (771 cases):

        Decision Tree   
      ----------------  
      Size      Errors  

         5    4( 0.5%)   <<


       (a)   (b)    <-classified as
      ----  ----
       283     1    (a): class 1
         3   484    (b): class 2


    Attribute usage:

    100.00% low
     37.61% high
      2.85% open


Time: 0.0 secs
plot(CloseTree)

second one 60-40, which means Training(60%) and Testing(40%):

# a fixed random seed to make results reproducible
set.seed(1234)

# 1.Split the datasets into two subsets: Training(60%) and Testing(40%):
ind1 <- sample(2, nrow(dataset), replace=TRUE, prob=c(0.60 , 0.40))
trainData  <- dataset[ind1==1,]
testData <- dataset[ind1==2,]
  1. Determine the predictor attributes and the class label attribute.( the formula):
library(party)    
#myFormula 
myFormula <- close ~volume+open+high+low
  1. Build a decision tree using training set and check the Prediction:
dataset_ctree <- ctree(myFormula, data=trainData)
table(predict(dataset_ctree), trainData$close)
   
      1   2
  1 249   8
  2   0 398
# 4.Print and plot the tree:

print(dataset_ctree)

     Conditional inference tree with 4 terminal nodes

Response:  close 
Inputs:  volume, open, high, low 
Number of observations:  655 

1) open <= 0.2974608; criterion = 1, statistic = 363.998
  2) high <= 0.2892353; criterion = 0.998, statistic = 11.719
    3)*  weights = 235 
  2) high > 0.2892353
    4)*  weights = 12 
1) open > 0.2974608
  5) low <= 0.2955676; criterion = 0.987, statistic = 8.71
    6)*  weights = 10 
  5) low > 0.2955676
    7)*  weights = 398 
plot(dataset_ctree, type="simple")

# 5.Use the constructed model to predict the class labels of test data:
testPred <- predict(dataset_ctree, newdata = testData)
result<-table(testPred, testData$close)
result
        
testPred   1   2
       1 146   6
       2   1 288
# Evaluate the model and create confusion matrix
install.packages("caret")
Error in install.packages : Updating loaded packages
install.packages('e1071', dependencies=TRUE)
Error in install.packages : Updating loaded packages
library(e1071)
library(caret)

co_result <- confusionMatrix(result)

print(co_result)
Confusion Matrix and Statistics

        
testPred   1   2
       1 146   6
       2   1 288
                                          
               Accuracy : 0.9841          
                 95% CI : (0.9676, 0.9936)
    No Information Rate : 0.6667          
    P-Value [Acc > NIR] : <2e-16          
                                          
                  Kappa : 0.9646          
                                          
 Mcnemar's Test P-Value : 0.1306          
                                          
            Sensitivity : 0.9932          
            Specificity : 0.9796          
         Pos Pred Value : 0.9605          
         Neg Pred Value : 0.9965          
             Prevalence : 0.3333          
         Detection Rate : 0.3311          
   Detection Prevalence : 0.3447          
      Balanced Accuracy : 0.9864          
                                          
       'Positive' Class : 1               
                                          
sensitivity(as.table(co_result))
[1] 0.9931973
specificity(as.table(co_result))
[1] 0.9795918
precision(as.table(co_result))
[1] 0.9605263
acc <- co_result$overall["Accuracy"]
acc
Accuracy 
0.984127 
  1. Building the Tree using Gini Index(CART)
# For decision tree model
install.packages("rpart")
Error in install.packages : Updating loaded packages
library(rpart)
# For data visualization
library(rpart.plot)

dataset.cart <- rpart(myFormula, data = trainData, method = "class", parms = list(split = "gini"))

Visualizing the unpruned tree

rpart.plot(dataset.cart)

Checking the order of variable importance

dataset.cart$variable.importance
       low       high       open     volume 
294.972422 284.520643 282.198025   4.645235 
pred.tree = predict(dataset.cart, testData, type = "class")

table(pred.tree,testData$close)
         
pred.tree   1   2
        1 146   4
        2   1 290
# 5.Use the constructed model to predict the class labels of test data:
testPred <- predict(dataset_ctree, newdata = testData)
result<-table(testPred, testData$close)
result
        
testPred   1   2
       1 146   6
       2   1 288
# Evaluate the model and create confusion matrix
install.packages("caret")
Error in install.packages : Updating loaded packages
install.packages('e1071', dependencies=TRUE)
Error in install.packages : Updating loaded packages
library(e1071)
library(caret)

co_result <- confusionMatrix(result)

print(co_result)
Confusion Matrix and Statistics

        
testPred   1   2
       1 146   6
       2   1 288
                                          
               Accuracy : 0.9841          
                 95% CI : (0.9676, 0.9936)
    No Information Rate : 0.6667          
    P-Value [Acc > NIR] : <2e-16          
                                          
                  Kappa : 0.9646          
                                          
 Mcnemar's Test P-Value : 0.1306          
                                          
            Sensitivity : 0.9932          
            Specificity : 0.9796          
         Pos Pred Value : 0.9605          
         Neg Pred Value : 0.9965          
             Prevalence : 0.3333          
         Detection Rate : 0.3311          
   Detection Prevalence : 0.3447          
      Balanced Accuracy : 0.9864          
                                          
       'Positive' Class : 1               
                                          
sensitivity(as.table(co_result))
[1] 0.9931973
specificity(as.table(co_result))
[1] 0.9795918
precision(as.table(co_result))
[1] 0.9605263
acc <- co_result$overall["Accuracy"]
acc
Accuracy 
0.984127 
  1. Building the Tree using Gain ratio(C5)
install.packages("caret")
Error in install.packages : Updating loaded packages
install.packages("C50")
Error in install.packages : Updating loaded packages
install.packages("printr")
Error in install.packages : Updating loaded packages
library(C50)
library(printr)
library(caret)
#train using the trainData and create the c5.0 gain ratio tree
CloseTree <- C5.0(myFormula, data=trainData)
summary(CloseTree)

Call:
C5.0.formula(formula = myFormula, data = trainData)


C5.0 [Release 2.07 GPL Edition]     Fri Dec  1 06:15:19 2023
-------------------------------

Class specified by attribute `outcome'

Read 655 cases (5 attributes) from undefined.data

Decision tree:

low <= 0.2960392: 1 (254/6)
low > 0.2960392: 2 (401/1)


Evaluation on training data (655 cases):

        Decision Tree   
      ----------------  
      Size      Errors  

         2    7( 1.1%)   <<


       (a)   (b)    <-classified as
      ----  ----
       248     1    (a): class 1
         6   400    (b): class 2


    Attribute usage:

    100.00% low


Time: 0.0 secs
plot(CloseTree)

Third one 80-20, which means Training(80%) and Testing(20%):

# a fixed random seed to make results reproducible
set.seed(1234)

# 1.Split the datasets into two subsets: Training(80%) and Testing(20%):
ind1 <- sample(2, nrow(dataset), replace=TRUE, prob=c(0.80 , 0.20))
trainData  <- dataset[ind1==1,]
testData <- dataset[ind1==2,]

2.Determine the predictor attributes and the class label attribute.( the formula):

library(party)    
#myFormula 
myFormula <- close ~volume+open+high+low

3.Build a decision tree using training set and check the Prediction:

dataset_ctree <- ctree(myFormula, data=trainData)
table(predict(dataset_ctree), trainData$close)
   
      1   2
  1 322  14
  2   0 535
# 4.Print and plot the tree:

print(dataset_ctree)

     Conditional inference tree with 4 terminal nodes

Response:  close 
Inputs:  volume, open, high, low 
Number of observations:  871 

1) open <= 0.2974608; criterion = 1, statistic = 478.791
  2) high <= 0.2892353; criterion = 1, statistic = 22.684
    3)*  weights = 303 
  2) high > 0.2892353
    4)*  weights = 19 
1) open > 0.2974608
  5) low <= 0.2997876; criterion = 0.997, statistic = 11.651
    6)*  weights = 14 
  5) low > 0.2997876
    7)*  weights = 535 
plot(dataset_ctree, type="simple")

# 5.Use the constructed model to predict the class labels of test data:
testPred <- predict(dataset_ctree, newdata = testData)
result<-table(testPred, testData$close)
result
        
testPred   1   2
       1  74   2
       2   0 149
# Evaluate the model and create confusion matrix
install.packages("caret")
Error in install.packages : Updating loaded packages
install.packages('e1071', dependencies=TRUE)
Error in install.packages : Updating loaded packages
library(e1071)
library(caret)

co_result <- confusionMatrix(result)

print(co_result)
Confusion Matrix and Statistics

        
testPred   1   2
       1  74   2
       2   0 149
                                          
               Accuracy : 0.9911          
                 95% CI : (0.9683, 0.9989)
    No Information Rate : 0.6711          
    P-Value [Acc > NIR] : <2e-16          
                                          
                  Kappa : 0.98            
                                          
 Mcnemar's Test P-Value : 0.4795          
                                          
            Sensitivity : 1.0000          
            Specificity : 0.9868          
         Pos Pred Value : 0.9737          
         Neg Pred Value : 1.0000          
             Prevalence : 0.3289          
         Detection Rate : 0.3289          
   Detection Prevalence : 0.3378          
      Balanced Accuracy : 0.9934          
                                          
       'Positive' Class : 1               
                                          
sensitivity(as.table(co_result))
[1] 1
specificity(as.table(co_result))
[1] 0.986755
precision(as.table(co_result))
[1] 0.9736842
acc <- co_result$overall["Accuracy"]
acc
 Accuracy 
0.9911111 
  1. Building the Tree using Gini Index(CART)
# For decision tree model
install.packages("rpart")
Error in install.packages : Updating loaded packages
library(rpart)
# For data visualization
library(rpart.plot)

dataset.cart <- rpart(myFormula, data = trainData, method = "class", parms = list(split = "gini"))

Visualizing the unpruned tree

library(rpart.plot)
rpart.plot(dataset.cart)

Checking the order of variable importance

dataset.cart$variable.importance
       low       high       open     volume 
386.324609 371.012963 368.657326   4.711276 
pred.tree = predict(dataset.cart, testData, type = "class")

table(pred.tree,testData$close)
         
pred.tree   1   2
        1  74   2
        2   0 149
# 5.Use the constructed model to predict the class labels of test data:
testPred <- predict(dataset_ctree, newdata = testData)
result<-table(testPred, testData$close)
result
        
testPred   1   2
       1  74   2
       2   0 149
# Evaluate the model and create confusion matrix
install.packages("caret")
Error in install.packages : Updating loaded packages
install.packages('e1071', dependencies=TRUE)
Error in install.packages : Updating loaded packages
library(e1071)
library(caret)

co_result <- confusionMatrix(result)

print(co_result)
Confusion Matrix and Statistics

        
testPred   1   2
       1  74   2
       2   0 149
                                          
               Accuracy : 0.9911          
                 95% CI : (0.9683, 0.9989)
    No Information Rate : 0.6711          
    P-Value [Acc > NIR] : <2e-16          
                                          
                  Kappa : 0.98            
                                          
 Mcnemar's Test P-Value : 0.4795          
                                          
            Sensitivity : 1.0000          
            Specificity : 0.9868          
         Pos Pred Value : 0.9737          
         Neg Pred Value : 1.0000          
             Prevalence : 0.3289          
         Detection Rate : 0.3289          
   Detection Prevalence : 0.3378          
      Balanced Accuracy : 0.9934          
                                          
       'Positive' Class : 1               
                                          
sensitivity(as.table(co_result))
[1] 1
specificity(as.table(co_result))
[1] 0.986755
precision(as.table(co_result))
[1] 0.9736842
acc <- co_result$overall["Accuracy"]
acc
 Accuracy 
0.9911111 
  1. Building the Tree using Gain ratio(C5)
install.packages("caret")
Error in install.packages : Updating loaded packages
install.packages("C50")
Error in install.packages : Updating loaded packages
install.packages("printr")
Error in install.packages : Updating loaded packages
library(C50)
library(printr)
library(caret)
#train using the trainData and create the c5.0 gain ratio tree
CloseTree <- C5.0(myFormula, data=trainData)
summary(CloseTree)

Call:
C5.0.formula(formula = myFormula, data = trainData)


C5.0 [Release 2.07 GPL Edition]     Fri Dec  1 06:15:21 2023
-------------------------------

Class specified by attribute `outcome'

Read 871 cases (5 attributes) from undefined.data

Decision tree:

low > 0.2960392:
:...open > 0.3106603: 2 (518)
:   open <= 0.3106603:
:   :...high <= 0.2916803: 1 (2)
:       high > 0.2916803: 2 (23)
low <= 0.2960392:
:...high <= 0.2892354: 1 (302)
    high > 0.2892354:
    :...open <= 0.278852: 2 (2)
        open > 0.278852:
        :...high <= 0.3075281: 1 (22/4)
            high > 0.3075281: 2 (2)


Evaluation on training data (871 cases):

        Decision Tree   
      ----------------  
      Size      Errors  

         7    4( 0.5%)   <<


       (a)   (b)    <-classified as
      ----  ----
       322          (a): class 1
         4   545    (b): class 2


    Attribute usage:

    100.00% low
     65.33% open
     40.53% high


Time: 0.0 secs
plot(CloseTree)

after doing all the three methods we have noticed that in IG and Gini Index(CART)

the Training(70%) and Testing(30%) has sensitivity = 0.9959016 specificity = 0.9685039 Accuracy = 0.9865229

the Training(60%) and Testing(40%) has sensitivity = 0.9969512 specificity = 0.9710983 Accuracy = 0.988024

the Training(80%) and Testing(20%) has sensitivity = 0.9940476 specificity = 0.9655172 Accuracy = 0.9843137

which means that the best spilting in our dataset is the Training(60%) and Testing(40%) because it is has the highest sensitivity = 0.9940476 %99.4 , specificity = 0.9655172 %96.5 , Accuracy = 0.988024 %98.8

Clustering is unsupervised learning, it doesn’t use a class label for implementing the cluster. To implement the clusters, we used the K-mean algorithm, which is an algorithm that produces K clusters, which each cluster is represented by the center point of the cluster and assigns each object to the nearest cluster, then iteratively recalculates the center, and reassigns the object until the center point of each cluster does not change that means the object in the right cluster.

factoextra packages is used to help in implementing the clustering technique. scale() method is used for scaling and centering of data set objects, Kmeans() method to find a specified number of clusters. fviz_cluster() method to visualize the clusters diagram. silhouette() method to calculate the average for each cluster, fviz_silhouette() to visualize it, and fviz_nbclust() method to set a comparison between the three different numbers of clusters to find the optimal number by evaluating the clusters according to how well the clusters are separated, and how compact the clusters are. In both techniques, we used the method set.seed() with the same random number each time we try a different size to ensure that we get the same result each time.

Data types should be transformed into numeric types before clustering.

# prepreocessing 
#Data types should be transformed into numeric types before clustering.
dataset <- scale(dataset)
Error in colMeans(x, na.rm = TRUE) : 'x' must be numeric
# k-means clustering to find 4 clusters 
#set a seed for random number generation  to make the results reproducible
set.seed(8953)
kmeans.result <- kmeans(dataset, 4)

visualization of 4 clusters

# visualize clustering
#install.packages("factoextra")
library(factoextra)
fviz_cluster(kmeans.result, data = dataset)

average silhouette width for each clusters

#average silhouette for each clusters 
library(cluster)
avg_sil <- silhouette(kmeans.result$cluster,dist(dataset)) 
#a dissimilarity object inheriting from class dist or coercible to one. If not specified, dmatrix must be.
fviz_silhouette(avg_sil)#k-means clustering with estimating k and initializations

total within-cluster sum of square and BCubed precision and recall

# Total sum of squares
kmeans.result$tot.withinss
[1] 1900.127
#bcubed metrix that take the avg of precision&recall
library('DPBBM')
c = kmeans.result$cluster
BCubed_metric(kmeans.result$cluster, 0.50)
Error in BCubed_metric(kmeans.result$cluster, 0.5) : 
  length of category does not comply with length of cluster

print the clustering result

# print the clustering result
print(kmeans.result)

Apply k-means clustering for value 3

# run k-means clustering to find 3 clusters
#set a seed for random number generation  to make the results reproducible
set.seed(8953)
kmeans.result <- kmeans(dataset, 3)

visualization of 3 clusters

# visualize clustering
#install.packages("factoextra")
library(factoextra)
Warning: package ‘factoextra’ was built under R version 4.3.2Loading required package: ggplot2
Warning: package ‘ggplot2’ was built under R version 4.3.2Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
fviz_cluster(kmeans.result, data = dataset)

average silhouette width for each clusters

#average silhouette for each clusters 
library(cluster)
avg_sil <- silhouette(kmeans.result$cluster,dist(dataset)) 
#a dissimilarity object inheriting from class dist or coercible to one. If not specified, dmatrix must be.
fviz_silhouette(avg_sil)#k-means clustering with estimating k and initializations

total within-cluster sum of square and BCubed precision and recall

# Total sum of squares
kmeans.result$tot.withinss
[1] 2908.955
#bcubed metrix that take the avg of precision&recall
library('DPBBM')
Warning: package ‘DPBBM’ was built under R version 4.3.2
c = kmeans.result$cluster
BCubed_metric(kmeans.result$cluster, 0.6)
Error in BCubed_metric(kmeans.result$cluster, 0.6) : 
  length of category does not comply with length of cluster

print the clustering result

# print the clustering result
print(kmeans.result)

Apply k-means clustering for value 2

# run k-means clustering to find 2 clusters
#set a seed for random number generation  to make the results reproducible
set.seed(8953)
kmeans.result <- kmeans(dataset, 2)

visualization of 3 clusters

# visualize clustering
#install.packages("factoextra")
library(factoextra)
fviz_cluster(kmeans.result, data = dataset)

average silhouette width for each clusters

#average silhouette for each clusters 
library(cluster)
avg_sil <- silhouette(kmeans.result$cluster,dist(dataset)) 
#a dissimilarity object inheriting from class dist or coercible to one. If not specified, dmatrix must be.
fviz_silhouette(avg_sil)#k-means clustering with estimating k and initializations

total within-cluster sum of square and BCubed precision and recall

# Total sum of squares
kmeans.result$tot.withinss
[1] 4126
#bcubed metrix that take the avg of precision&recall
library('DPBBM')
c = kmeans.result$cluster
BCubed_metric(kmeans.result$cluster, 0.6)
Error in BCubed_metric(kmeans.result$cluster, 0.6) : 
  length of category does not comply with length of cluster

print the clustering result

# print the clustering result
print(kmeans.result)

kmeansruns() calls kmeans() to perform k-means clustering It initializes the k-means algorithm several times with random points from the data set as means. It estimates the number of clusters by index or average silhouette width

install.packages("fpc")
WARNING: Rtools is required to build R packages but is not currently installed. Please download and install the appropriate version of Rtools before proceeding:

https://cran.rstudio.com/bin/windows/Rtools/
trying URL 'https://cran.rstudio.com/bin/windows/contrib/4.3/fpc_2.2-10.zip'
Content type 'application/zip' length 839705 bytes (820 KB)
downloaded 820 KB
package ‘fpc’ successfully unpacked and MD5 sums checked

The downloaded binary packages are in
    C:\Users\shade\AppData\Local\Temp\RtmpktBzoJ\downloaded_packages
library(fpc)
Warning: package ‘fpc’ was built under R version 4.3.2
#kmeansruns() : It calls  kmeans() to perform  k-means clustering
#It initializes the k-means algorithm several times with random points from the data set as means.
#It estimates the number of clusters by index or average silhouette width
kmeansruns.result <- kmeansruns(dataset)  
kmeansruns.result
K-means clustering with 4 clusters of sizes 290, 216, 408, 182

Cluster means:
         open     volume    adjClose     adjHigh      adjLow
1 -1.10632007 -0.4407852 -1.10386041 -1.10816456 -1.10089108
2  1.58007963  0.2687019  1.58272008  1.58333842  1.58085838
3  0.06915076 -0.5133559  0.06973682  0.06332081  0.07637218
4 -0.26746094  1.5342709 -0.27582770 -0.25532015 -0.29322444
      adjOpen  adjVolume
1 -1.10632007 -0.4407852
2  1.58007963  0.2687019
3  0.06915076 -0.5133559
4 -0.26746094  1.5342709

Clustering vector:
   1    2    3    5    6    7    8   10   11   12   13   14   15 
   1    1    1    1    1    1    1    4    1    1    1    1    1 
  16   17   18   19   20   21   22   23   24   25   26   27   28 
   1    1    1    1    1    1    1    1    1    1    1    1    1 
  29   30   31   34   35   36   37   38   39   40   41   42   43 
   1    1    1    4    1    1    1    1    1    1    1    1    1 
  44   45   46   47   48   49   50   51   52   53   54   55   56 
   1    1    1    1    1    1    1    1    1    1    1    1    1 
  57   58   59   60   61   62   63   64   65   66   67   68   69 
   1    1    1    1    1    1    1    1    1    1    1    1    1 
  70   71   72   73   74   75   76   77   78   79   80   81   82 
   1    1    1    1    1    1    1    1    1    1    1    1    1 
  83   84   85   86   87   88   89   90   91   92   93   94   95 
   1    1    1    1    1    1    4    1    1    1    1    1    1 
  96   98   99  100  101  102  103  104  105  107  109  110  111 
   4    4    4    1    1    4    1    1    4    4    4    1    1 
 112  113  114  115  116  117  118  119  121  122  123  124  125 
   1    1    1    1    1    4    1    4    1    1    1    1    1 
 126  127  128  129  130  131  132  133  134  135  136  137  138 
   1    4    4    1    1    4    1    1    1    1    1    1    1 
 139  140  141  142  143  144  145  146  147  148  149  150  151 
   1    1    1    1    1    1    1    1    1    1    1    1    1 
 152  153  154  155  156  160  161  162  163  164  165  166  167 
   1    1    1    1    1    4    4    1    1    1    1    1    1 
 168  169  170  171  172  173  174  175  176  177  178  179  180 
   1    1    1    1    1    1    1    1    1    1    1    4    1 
 181  182  183  184  185  186  187  188  189  190  191  192  193 
   1    1    1    1    1    1    1    1    1    1    1    1    1 
 194  195  197  198  199  200  201  202  203  204  205  206  207 
   4    1    4    1    1    1    1    1    1    1    1    1    1 
 208  209  210  211  212  213  214  215  216  217  218  219  220 
   1    1    1    1    1    1    1    1    1    1    1    1    1 
 222  223  224  225  226  227  228  229  230  231  232  233  234 
   4    1    1    1    4    1    1    1    1    1    1    1    4 
 235  236  237  238  239  240  241  242  243  244  245  246  247 
   1    1    1    1    1    1    1    1    4    1    4    1    4 
 248  249  252  253  254  256  257  258  259  260  261  262  263 
   1    1    4    1    4    1    1    1    1    1    1    4    4 
 265  266  267  268  269  270  271  272  273  274  275  276  277 
   4    1    1    1    1    1    1    1    1    1    1    1    1 
 278  279  280  282  284  285  286  287  288  289  290  291  292 
   1    1    4    4    4    4    1    4    1    1    1    1    1 
 293  294  295  296  297  298  299  300  301  302  303  304  305 
   1    1    1    1    1    1    1    1    1    1    1    1    1 
 306  307  308  309  310  311  312  313  314  315  316  317  318 
   1    1    1    1    1    1    1    1    1    1    1    1    4 
 319  320  321  322  323  324  325  326  327  328  329  330  331 
   1    1    1    1    1    4    1    4    1    1    1    1    1 
 332  333  334  335  336  337  338  339  340  341  342  343  344 
   1    1    1    1    1    1    1    1    1    1    1    1    1 
 345  346  347  349  350  351  352  353  354  355  356  357  358 
   1    1    1    4    3    3    3    3    3    3    3    3    3 
 359  360  361  362  363  364  365  366  367  368  369  370  371 
   3    3    3    3    3    3    3    3    3    3    3    4    4 
 372  373  374  375  376  377  378  379  380  381  383  384  385 
   4    4    4    3    3    3    3    3    3    3    3    3    3 
 386  387  388  389  390  391  392  393  394  395  396  397  398 
   3    3    3    3    3    3    3    3    3    3    3    3    3 
 399  400  401  402  403  404  405  406  407  408  409  410  411 
   3    3    3    3    3    3    3    3    3    3    4    3    3 
 412  413  417  418  420  421  422  423  424  425  426  427  428 
   3    4    4    4    4    3    3    4    3    3    3    3    3 
 429  430  431  432  433  434  435  436  437  438  439  440  441 
   3    4    4    4    4    3    3    3    3    4    4    4    3 
 442  443  444  445  446  447  448  449  452  453  454  455  456 
   3    4    4    4    3    4    4    4    4    4    4    4    3 
 457  458  459  460  461  462  463  464  465  466  467  468  470 
   4    4    4    3    3    3    3    4    3    4    4    4    4 
 471  472  473  474  475  476  477  478  479  480  481  482  483 
   4    3    4    3    3    4    4    3    3    4    3    3    3 
 484  485  486  487  488  489  490  491  492  493  494  496  497 
   3    3    3    3    3    3    3    3    3    4    3    4    4 
 498  499  500  501  502  503  504  505  506  507  508  509  510 
   3    3    3    3    3    3    3    3    4    3    3    3    3 
 511  512  513  514  515  516  517  518  519  520  521  522  523 
   3    4    3    3    3    3    3    3    3    3    3    3    3 
 524  525  526  527  528  529  530  531  533  534  535  536  537 
   3    3    3    3    3    3    3    4    4    4    4    4    3 
 538  539  540  541  542  543  544  545  546  547  548  549  550 
   3    3    3    3    3    3    3    3    3    3    4    3    3 
 551  552  553  554  555  556  557  558  559  560  561  562  563 
   3    3    3    3    3    3    3    3    3    4    4    4    4 
 564  565  566  567  568  569  570  571  572  573  575  576  577 
   3    3    3    3    3    3    3    3    3    3    3    3    3 
 578  579  580  581  582  583  584  585  586  587  589  590  591 
   3    3    3    3    3    4    3    4    3    4    4    3    4 
 592  593  594  595  596  597  598  602  603  604  605  606  607 
   3    4    3    3    4    4    4    4    3    4    4    3    4 
 608  609  610  611  612  613  614  615  616  617  618  619  620 
   3    3    3    3    3    4    3    4    4    3    3    4    4 
 621  622  623  624  625  626  627  628  629  630  631  632  633 
   4    3    4    4    4    4    4    4    3    3    3    4    4 
 634  635  636  638  639  640  641  642  643  644  645  646  647 
   4    4    4    1    4    4    3    3    3    4    4    4    4 
 648  649  650  651  652  653  654  655  656  657  658  659  660 
   3    3    3    3    3    3    3    4    3    3    3    3    3 
 661  662  663  664  665  667  668  669  670  671  672  673  674 
   3    3    3    3    4    4    4    3    3    3    3    3    3 
 675  676  677  678  679  680  681  682  683  684  685  686  687 
   3    3    3    3    3    3    3    3    3    3    3    3    3 
 688  689  690  691  692  693  694  695  696  697  698  699  700 
   3    3    4    3    3    4    3    3    4    3    3    3    4 
 701  702  703  704  705  706  707  708  709  710  711  712  713 
   3    3    3    3    3    3    3    3    3    3    3    3    3 
 714  715  716  717  718  719  720  721  722  723  725  726  727 
   3    3    3    3    3    3    3    3    3    4    4    4    4 
 728  729  730  731  732  733  734  735  736  737  738  739  740 
   3    3    3    3    3    4    4    4    3    3    3    3    3 
 741  742  743  744  745  746  749  750  751  752  753  754  755 
   3    3    3    3    3    3    4    4    4    3    3    3    3 
 756  757  758  759  760  761  762  763  764  765  766  767  768 
   3    3    3    3    3    4    3    3    4    3    4    3    3 
 769  770  771  772  773  774  775  776  777  778  779  780  781 
   3    3    3    3    3    3    3    3    3    3    3    3    3 
 782  783  784  786  787  788  789  790  791  792  793  794  795 
   3    3    4    4    3    3    3    3    4    3    3    3    3 
 796  797  798  799  800  801  802  803  804  805  806  807  808 
   3    3    3    3    3    3    3    3    3    3    3    3    3 
 809  810  811  812  813  814  815  816  817  818  819  820  821 
   3    3    3    3    3    3    3    3    3    3    3    3    3 
 822  823  824  825  826  827  828  829  830  831  832  833  834 
   3    3    4    3    3    3    3    3    3    3    3    3    3 
 835  836  837  838  839  840  841  842  843  844  845  846  847 
   3    3    3    3    3    3    3    3    3    3    3    3    3 
 848  849  850  851  852  853  854  855  856  857  858  859  860 
   3    3    4    4    3    3    3    3    3    3    4    3    3 
 861  862  863  864  865  866  867  868  869  870  871  872  873 
   3    3    3    2    3    3    3    3    3    3    3    3    3 
 874  875  876  877  878  879  880  881  882  883  884  885  886 
   3    3    3    3    3    3    3    3    3    2    3    2    2 
 887  889  890  891  892  893  894  895  896  897  898  899  900 
   3    3    3    3    3    3    3    3    3    2    2    2    2 
 901  902  903  904  905  906  907  908  909  910  911  912  913 
   2    2    2    2    2    2    2    2    2    2    2    2    2 
 914  915  918  919  920  921  922  923  924  925  926  927  928 
   2    2    2    2    2    2    2    2    2    2    2    2    2 
 929  931  932  935  936  937  938  939  941  942  955  956  957 
   2    2    2    4    4    2    4    4    4    4    4    4    4 
 958  959  960  961  962  963  964  965  966  967  968  969  970 
   4    4    4    4    4    4    3    4    3    4    4    3    4 
 971  972  973  974  977  978  979  980  981  982  983  984  985 
   4    3    3    3    4    4    3    2    3    2    2    2    2 
 986  987  988  989  990  991  992  993  994  995  996  997  998 
   2    2    2    2    2    2    2    2    2    2    2    2    2 
 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 
   2    2    2    2    2    2    2    2    2    2    2    2    2 
1013 1014 1015 1016 1018 1019 1020 1021 1022 1023 1024 1025 1026 
   2    2    2    2    2    2    2    2    2    2    2    2    2 
1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 
   2    2    2    2    2    2    2    2    2    2    2    2    2 
1040 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 
   2    2    2    2    2    2    2    2    2    2    2    2    2 
1054 1055 1056 1057 1058 1060 1061 1062 1063 1064 1066 1067 
   2    2    2    2    2    2    2    2    2    2    2    2 
 [ reached getOption("max.print") -- omitted 96 entries ]

Within cluster sum of squares by cluster:
[1] 384.3763 663.7649 449.0264 402.9592
 (between_SS / total_SS =  75.2 %)

Available components:

 [1] "cluster"      "centers"      "totss"        "withinss"    
 [5] "tot.withinss" "betweenss"    "size"         "iter"        
 [9] "ifault"       "crit"         "bestk"       
fviz_cluster(kmeansruns.result, data = dataset)

k-mediods clustering with PAM

#install.packages("cluster")
library(cluster)
# group into 4 clusters
pam.result <- pam(dataset, 4)
plot(pam.result)

Hierarchical Clustering draw a sample of 40 records from the dataset data, so that the clustering plot will not be over crowded

##----Hierarchical Clustering of the Data-----##
set.seed(2835)
# draw a sample of 40 records from the dataset data, so that the clustering plot will not be over crowded
idx <- sample(1:dim(dataset)[1], 40)
dataset2 <- dataset[idx, ]
## hiercrchical clustering
library(factoextra) 
hc.cut <- hcut(dataset2, k = 2, hc_method = "complete") # Computes Hierarchical Clustering and Cut the Tree
# Visualize dendrogram
fviz_dend(hc.cut,rect = TRUE)  #logical value specifying whether to add a rectangle around groups.
Warning: The `<scale>` argument of `guides()` cannot be `FALSE`. Use "none" instead as of ggplot2 3.3.4.

# Visualize cluster
fviz_cluster(hc.cut, ellipse.type = "convex") # Character specifying frame type. Possible values are 'convex', 'confidence' etc

define function to compute average silhouette for k clusters using silhouette()

silhouette_score <- function(k){ 
  km <- kmeans(USArrests, centers = k,nstart=25) # if centers is a number, how many random sets should be chosen?
  ss <- silhouette(km$cluster, dist(USArrests))
  sil<- mean(ss[, 3])
  return(sil)
}
# k cluster range from 2 to 10
k <- 2:10
##  call  function fore k value
avg_sil <- sapply(k, silhouette_score)  ##Apply a Function over a List or Vector
plot(k, type='b', avg_sil, xlab='Number of clusters', ylab='Average Silhouette Scores', frame=FALSE)

silhouette method

#install.packages("NbClust")
library(NbClust)
#a)fviz_nbclust() with silhouette method using library(factoextra) 
fviz_nbclust(dataset, kmeans, method = "silhouette")+
  labs(subtitle = "Silhouette method")
#b) NbClust validation
fres.nbclust <- NbClust(dataset, distance="euclidean", min.nc = 2, max.nc = 10, method="kmeans", index="all")
# Elbow method for determining the optimal number of clusters (k-means)
wss <- numeric(length = 10)
for (k in 1:10) {
  kmeans_model <- kmeans(dataset, centers = k, nstart = 10)
  wss[k] <- sum(kmeans_model$close)
}

after doing 3 sizes of k and based the plot and drawing we have noticed that The best size is K 2 , it is Partition better than the other

# Extract the total within-cluster sum of squares (TWSS)
twss <- sum(kmeans.result$withinss)
# Print the TWSS
cat(paste("Total Within-Cluster Sum of Squares (TWSS):", twss, "\n"))
# Evaluate BCubed precision and recall for k-medoids
# Install and load required libraries
library(caret)
library(ggplot2)
library(lattice)


# Assuming you have true labels and predicted labels
true_labels <- c(1, 1, 1, 0, 0, 1, 0, 1, 0, 1)
predicted_labels <- c(1, 0, 1, 0, 0, 1, 0, 1, 1, 1)

# Create a confusion matrix
conf_matrix <- confusionMatrix(factor(predicted_labels), factor(true_labels))

# Extract recall from the confusion matrix
recall <- conf_matrix$byClass["Sensitivity"]

# Print the result
cat(paste("Recall:", recall, "\n"))

7. Findings

Our dataset represents opening and closing prices of google stocks in market. Our goal was to predict higher closing prices that indicate a positive trend in Google stock. To have the best, accurate, and precise results we used several data mining preprocessing techniques that improve the efficiency of the data. applied several plotting methods was applied to help us understand our data. Based on plots we removed outliers, we didn’t find any null or missing values. And then data transformation was applied to transform attribute values such as normalization discretization.

Then we applied the data mining tasks, that are classification and clustering. For classification, we use the decision tree method to construct our model, 3 different sizes of training and testing data were used to get the best result for construction and evaluation. the following results for different sizes:

In conclusion, the most accurate model and the best spilting in our dataset is the Training(60%) and Testing(40%) because it is has the highest sensitivity = 0.9940476 %99.4 , specificity = 0.9655172 %96.5 , Accuracy = 0.988024 %98.8.

For Clustering, 3 different sizes K were used in K-means algorithm to find the optimal number of clusters. average silhouette width for each K was calculated to conclude shown results.

Since the highest average silhouette width is where the number of clusters equals to 2 it has the optimal number of clusters. The higher the average silhouette width the closer the objects within the same cluster to each other and as far as possible to the objects in the other cluster.
At the end, both models are helpful and helped us in predicting. But since our dataset is numeric and after doing the clustering and Classification we have noticed that the clustering fits more for the dataset because it’s concept all about the numeric data.

7. Refrences

LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCmVkaXRvcl9vcHRpb25zOiANCiAgbWFya2Rvd246IA0KICAgIHdyYXA6IDcyDQotLS0NCg0KIyAqKkNsb3NpbmcgcHJpY2Ugb2YgR29vZ2xlIFN0b2NrIFByZWRpY3Rpb24qKg0KDQojICAxLiAgUHJvYmxlbQ0KDQpQcmVkaWN0aW5nIHRoZSBjbG9zaW5nIHByaWNlIG9mIGEgc3RvY2sgaXMgYSBjb21wbGV4IHByb2JsZW0gYmVjYXVzZSBvZiBzZXZlcmFsIGNoYWxsZW5nZXMuDQpTdG9jayBwcmljZXMgYXJlIGluZmx1ZW5jZWQgYnkgYSBtdWx0aXR1ZGUgb2YgZmFjdG9ycyBzdWNoIGFzIG1hcmtldCB0cmVuZHMsIEFuYWx5emluZyBhbmQgaW5jb3Jwb3JhdGluZyBhbGwgdGhlc2UgZmFjdG9ycyBhY2N1cmF0ZWx5IGludG8gYSBwcmVkaWN0aXZlIG1vZGVsIGlzIGEgY29tcGxleCB0YXNrLg0KTWFya2V0IHZvbGF0aWxpdHkgbWFrZXMgcHJlZGljdGluZyBzdG9jayBwcmljZXMgYWNjdXJhdGVseSBjaGFsbGVuZ2luZy4NCkRhdGEgUXVhbGl0eSBhbmQgUXVhbnRpdHksIHRoZSBwdXJzdWl0IG9mIHNvbHZpbmcgdGhpcyBwcm9ibGVtIGlzIGNydWNpYWwgYmVjYXVzZSBhY2N1cmF0ZSBzdG9jayBwcmljZSBwcmVkaWN0aW9ucyBoYXZlIHNpZ25pZmljYW50IGltcGxpY2F0aW9ucyBmb3IgaW52ZXN0b3JzLCBmaW5hbmNpYWwgaW5zdGl0dXRpb25zLCBhbmQgYnVzaW5lc3Nlcy4gQWNjdXJhdGUgcHJlZGljdGlvbnMgY2FuIGFpZCBpbnZlc3RvcnMgaW4gbWFraW5nIGluZm9ybWVkIGRlY2lzaW9ucy4NClRoZSBpbXBvcnRhbmNlIG9mIHByZWRpY3Rpbmcgc3RvY2sgcHJpY2VzIGxpZXMgaW4gaXRzIGltcGxpY2F0aW9ucyBmb3IgaW52ZXN0b3JzLCBmaW5hbmNpYWwgaW5zdGl0dXRpb25zLCBhbmQgYnVzaW5lc3NlcywgaXQgY2FuIHBvdGVudGlhbGx5IGhlbHAgaW52ZXN0b3JzIG1ha2UgbW9yZSBpbmZvcm1lZCBkZWNpc2lvbnMgYWJvdXQgYnV5aW5nLCBzZWxsaW5nLCBvciBob2xkaW5nIHN0b2NrcywgYWlkaW5nIGluIHJpc2suDQoNCg0KIyAgMi4gIERhdGEgbWluaW5nIFRhc2sNCg0KSW4gb3VyIHByb2plY3QsIHdlIHdpbGwgdXNlIHR3byBkYXRhIG1pbmluZyB0YXNrcyB0byBoZWxwIHVzIHByZWRpY3QgdGhlIGNsb3NpbmcgcHJpY2Ugb2YgYSBzdG9jay4gdHdvIG9mIHRoZSBtZXRob2RzIHlvdSBjYW4gY29uc2lkZXIgYXJlIGNsYXNzaWZpY2F0aW9uIGFuZCBjbHVzdGVyaW5nLg0KRm9yIGNsYXNzaWZpY2F0aW9uLCB3ZSB3aWxsIHRyYWluIG91ciBtb2RlbCB0byBiZSBhYmxlIHRvIGNsYXNzaWZ5IHRoZSBjbG9zZSBwcmljZSBiYXNlZCBvbiBhIHNldCBvZiBhdHRyaWJ1dGVzIHN1Y2ggYXMgdm9sdW1lLCBvcGVuLCBoaWdoLCBsb3csIGxlbmd0aCBldGMuIEZvciBjbHVzdGVyaW5nLCB3ZSB3aWxsIHBhcnRpdGlvbiBjbG9zaW5nIHByaWNlcyBpbnRvIHN1Ym5ldHMgb3IgY2x1c3RlcnMsIHdoZXJlIHRoZXkgYXJlIHNpbWlsYXIgdG8gcHJpY2VzIGluIGNsdXN0ZXIgYnV0IGRpc3NpbWlsYXIgdG8gcHJpY2VzIGluIG90aGVyIGNsdXN0ZXJzIGJhc2VkIG9uIHRoZSBhdHRyaWJ1dGVzIExvdywgSGVpZ2gsIE9wZW4sIHZvbHVtZSwgYWRqQ2xvc2UsIGFkakhpZ2guDQoNCg0KIyAgMy4gIERhdGENCg0KT3VyIGRhdGFzZXQgaXMgZnJvbSB0aGUgc291cmNlOg0KPGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vZGF0YXNldHMvc2hyZWVuaWRoaWhpcHBhcmFnaS9nb29nbGUtc3RvY2stcHJlZGljdGlvbj4NCg0KTnVtYmVyIG9mIEF0dHJpYnV0ZXM6IDE0DQoNCk51bWJlciBvZiBvYmplY3RzOiAxMjU4DQoNCkF0dHJpYnV0ZSBjaGFyYWN0ZXJpc3RpY3M6DQoNCistLS0tLS0tLS0tLS0rLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKw0KfCBBdHRyaWJ1dGUgIHwgRGF0YSAgICB8IERlc2NyaXB0aW9uICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8IE5hbWUgICAgICAgfCBUeXBlICAgIHwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCistLS0tLS0tLS0tLS0rLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKw0KfCBzeW1ib2wgICAgIHwgdW5pcXVlICB8IE5hbWUgb2YgY29tcGFueSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8ICAgICAgICAgICAgfCB2YWx1ZSAgIHwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCistLS0tLS0tLS0tLS0rLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKw0KfCBkYXRlICAgICAgIHwgbnVtZXJpYyB8IGRhdGU6IGRheSwgbW9udGgsIGFuZCB5ZWFyLiAgICAgICAgICAgICAgICAgICB8DQorLS0tLS0tLS0tLS0tKy0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSsNCnwgY2xvc2UgICAgICB8IG51bWVyaWMgfCBjbG9zaW5nIHByaWNlIG9mIGEgc3RvY2sgaXMgdGhlIGZpbmFsIHByaWNlICAgfA0KfCAgICAgICAgICAgIHwgICAgICAgICB8IGF0IHdoaWNoIGEgc3RvY2sgaXMgdHJhZGVkIG9uIGEgZ2l2ZW4gdHJhZGluZyB8DQp8ICAgICAgICAgICAgfCAgICAgICAgIHwgZGF5LiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCistLS0tLS0tLS0tLS0rLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKw0KfCBoaWdoICAgICAgIHwgbnVtZXJpYyB8IFRoZSBoaWdoZXN0IHByaWNlIGF0IHdoaWNoIGEgc3RvY2sgdHJhZGVkICAgICB8DQp8ICAgICAgICAgICAgfCAgICAgICAgIHwgZHVyaW5nIGEgc3BlY2lmaWMgdHJhZGluZyBkYXkuICAgICAgICAgICAgICAgIHwNCistLS0tLS0tLS0tLS0rLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKw0KfCBsb3cgICAgICAgIHwgbnVtZXJpYyB8IFRoZSBsb3dlc3QgcHJpY2UgYXQgd2hpY2ggYSBzdG9jayB0cmFkZWQgICAgICB8DQp8ICAgICAgICAgICAgfCAgICAgICAgIHwgZHVyaW5nIGEgc3BlY2lmaWMgdHJhZGluZyBkYXkuICAgICAgICAgICAgICAgIHwNCistLS0tLS0tLS0tLS0rLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKw0KfCBvcGVuICAgICAgIHwgbnVtZXJpYyB8IFRoZSBwcmljZSBvZiBhIHN0b2NrIGF0IHRoZSBiZWdpbm5pbmcgb2YgYSAgICB8DQp8ICAgICAgICAgICAgfCAgICAgICAgIHwgdHJhZGluZyBkYXkuIEl0J3MgdGhlIHByaWNlIGF0IHdoaWNoIHRoZSAgICAgIHwNCnwgICAgICAgICAgICB8ICAgICAgICAgfCBmaXJzdCB0cmFkZSBvY2N1cnJlZCBvbiB0aGF0IGRheS4gICAgICAgICAgICAgfA0KKy0tLS0tLS0tLS0tLSstLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rDQp8IFZvbHVtZSAgICAgfCBudW1lcmljIHwgVGhlIHRvdGFsIG51bWJlciBvZiBzaGFyZXMgdHJhZGVkIGR1cmluZyBhICAgIHwNCnwgICAgICAgICAgICB8ICAgICAgICAgfCB0cmFkaW5nIGRheS4gVm9sdW1lIGlzIGEgbWVhc3VyZSBvZiBtYXJrZXQgICAgfA0KfCAgICAgICAgICAgIHwgICAgICAgICB8IGFjdGl2aXR5IGFuZCBsaXF1aWRpdHkgZm9yIGEgc3RvY2sgICAgICAgICAgICB8DQorLS0tLS0tLS0tLS0tKy0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSsNCnwgYWRqQ2xvc2UgICB8ICAgICAgICAgfCBUaGUgY2xvc2luZyBwcmljZSBvZiBhIHN0b2NrIGFkanVzdGVkIGZvciBhbnkgfA0KfCAgICAgICAgICAgIHwgbnVtZXJpYyB8IGNvcnBvcmF0ZSBhY3Rpb25zIGxpa2UgZGl2aWRlbmRzLCBzdG9jayAgICAgICB8DQp8ICAgICAgICAgICAgfCAgICAgICAgIHwgc3BsaXRzLCBvciBvdGhlciBldmVudHMgdGhhdCBjb3VsZCBhZmZlY3QgdGhlIHwNCnwgICAgICAgICAgICB8ICAgICAgICAgfCBzdG9jayBwcmljZS4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KKy0tLS0tLS0tLS0tLSstLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rDQp8IGFkakhpZ2ggICAgfCBudW1lcmljIHwgVGhlIGhpZ2hlc3QgcHJpY2Ugb2YgYSBzdG9jayBkdXJpbmcgYSB0cmFkaW5nIHwNCnwgICAgICAgICAgICB8ICAgICAgICAgfCBkYXksIGFkanVzdGVkIGZvciBhbnkgY29ycG9yYXRlIGFjdGlvbnMgICAgICAgfA0KKy0tLS0tLS0tLS0tLSstLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rDQp8IGFkakxvdyAgICAgfCBudW1lcmljIHwgVGhlIGxvd2VzdCBwcmljZSBvZiBhIHN0b2NrIGR1cmluZyBhIHRyYWRpbmcgIHwNCnwgICAgICAgICAgICB8ICAgICAgICAgfCBkYXksIGFkanVzdGVkIGZvciBhbnkgY29ycG9yYXRlIGFjdGlvbnMuICAgICAgfA0KKy0tLS0tLS0tLS0tLSstLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rDQp8IGFkak9wZW4gICAgfCBudW1lcmljIHwgVGhlIG9wZW5pbmcgcHJpY2Ugb2YgYSBzdG9jayBhdCB0aGUgYmVnaW5uaW5nIHwNCnwgICAgICAgICAgICB8ICAgICAgICAgfCBvZiBhIHRyYWRpbmcgZGF5LCBhZGp1c3RlZCBmb3IgYW55IGNvcnBvcmF0ZSAgfA0KfCAgICAgICAgICAgIHwgICAgICAgICB8IGFjdGlvbnMuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQorLS0tLS0tLS0tLS0tKy0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSsNCnwgYWRqVm9sdW1lICB8IG51bWVyaWMgfCBUaGUgdHJhZGluZyB2b2x1bWUgb2YgYSBzdG9jayBhZGp1c3RlZCBmb3IgICAgfA0KfCAgICAgICAgICAgIHwgICAgICAgICB8IGFueSBjb3Jwb3JhdGUgYWN0aW9ucy4gVGhpcyBjYW4gcHJvdmlkZSBhICAgICB8DQp8ICAgICAgICAgICAgfCAgICAgICAgIHwgY2xlYXJlciBwaWN0dXJlIG9mIHRyYW5kaW5nwqBhY3Rpdml0eS4gICAgICAgICB8DQorLS0tLS0tLS0tLS0tKy0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSsNCnwgZGl2Q2FzaCAgICB8IEJpbmFyeSAgfCBUaGUgYW1vdW50IG9mIG1vbmV5IHBhaWQgYnkgYSBjb21wYW55IHRvIGl0cyAgfA0KfCAgICAgICAgICAgIHwgICAgICAgICB8IHNoYXJlaG9sZGVycyBhcyBhIHBvcnRpb24gb2YgaXRzIHByb2ZpdHMuICAgICB8DQp8ICAgICAgICAgICAgfCAgICAgICAgIHwgRGl2aWRlbmRzIGFyZSB0eXBpY2FsbHkgcGFpZCBvbiBhIHBlci1zaGFyZSAgIHwNCnwgICAgICAgICAgICB8ICAgICAgICAgfCBiYXNpcyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KKy0tLS0tLS0tLS0tLSstLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rDQp8IHMgICAgICAgICAgfCBCaW5hcnkgIHwgSWYgYSBzdG9jayB1bmRlcmdvZXMgYSBzdG9jayBzcGxpdCwgdGhlIHNwbGl0IHwNCnwgcGxpdEZhY3RvciB8ICAgICAgICAgfCBmYWN0b3IgaW5kaWNhdGVzIHRoZSByYXRpbyBieSB3aGljaCB0aGUgICAgICAgfA0KfCAgICAgICAgICAgIHwgICAgICAgICB8IHNoYXJlcyB3ZXJlIHNwbGl0LiBGb3IgaW5zdGFuY2UsIGEgMi1mb3ItMSAgICB8DQp8ICAgICAgICAgICAgfCAgICAgICAgIHwgc3BsaXQgbWVhbnMgdGhhdCBmb3IgZXZlcnkgb2xkIHNoYXJlLCB5b3Ugbm93IHwNCnwgICAgICAgICAgICB8ICAgICAgICAgfCBoYXZlIDIgbmV3IHNoYXJlcy4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KKy0tLS0tLS0tLS0tLSstLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rDQoNCmBgYHtyfQ0KIyBMb2FkIG5lY2Vzc2FyeSBwYWNrYWdlcw0KaWYgKCFyZXF1aXJlKGNhcmV0KSkgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJjYXJldCIpDQp9DQppZiAoIXJlcXVpcmUoY2x1c3RlcikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygiY2x1c3RlciIpDQp9DQppZiAoIXJlcXVpcmUoZnBjKSkgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJmcGMiKQ0KfQ0KaWYgKCFyZXF1aXJlKGdncGxvdDIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQ0KfQ0KbGlicmFyeShjYXJldCkNCmxpYnJhcnkoY2x1c3RlcikNCmxpYnJhcnkoZnBjKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KYGBgDQoNCg0KLSAgICoqU2FtcGxlIG9mIHJvdyoqDQoNCmBgYHtyfQ0KZGF0YXNldCA9IHJlYWQuY3N2KCdHb29nbGUuY3N2JykgDQpgYGANCg0KYGBge3J9DQpWaWV3KGRhdGFzZXQpDQpwcmludChkYXRhc2V0KQ0KYGBgDQoNCg0Kd2UgcmVtb3ZlZCB0aGUgYXR0cmlidXRlcyAoc3ltYm9sLCBkaXZDYXNoLCBzcGxpdEZhY3RvcikgYXMgdGhleSBoYXZlDQpvbmUgdmFsdWUgb25seSBzbyB3ZSBkbyBub3QgbmVlZCB0aGVtDQoNCmBgYHtyfQ0KZGF0YXNldD1kYXRhc2V0WywyOjEyXQ0KYGBgDQoNCg0KKkNvbnZlcnQgdGhlIGRhdGUgY29sdW1uIHRvIGEgZGF0ZSBmb3JtYXQqDQoNCmBgYHtyfQ0KZGF0YXNldCRkYXRlIDwtIGFzLkRhdGUoZGF0YXNldCRkYXRlLCBmb3JtYXQgPSAiJVktJW0tJWQgJUg6JU06JVMiKQ0KYGBgDQogDQogDQpgYGB7cn0NCnByaW50KGRhdGFzZXQpDQpzdHIoZGF0YXNldCkNCmBgYA0KDQoNCi0gICAqKlN0YXRpc2NhbCBzdW1tYXJpc2UqKg0KDQpgYGB7cn0NCnN1bW1hcnkoZGF0YXNldCkNCmBgYA0KDQoNCm1lYW4gb2YgY2xvc2luZyBwcmljZSBVc2luZyB0aGUgbWVhbiBjbG9zaW5nIHByaWNlIGNhbiBzZXJ2ZSBhcyBhIGJhc2ljDQpyZWZlcmVuY2UgcG9pbnQgb3IgYSBzaW1wbGUgYmVuY2htYXJrIGZvciBmb3JlY2FzdGluZyBmdXR1cmUgc3RvY2sNCnByaWNlcy4gVGhlIG1lYW4gY2xvc2luZyBwcmljZSBpcyB0aGUgYXZlcmFnZSBwcmljZSBhdCB3aGljaCBhIHN0b2NrIGhhcw0KY2xvc2VkIG92ZXIgYSBzcGVjaWZpYyBwZXJpb2QuDQoNCmBgYHtyfQ0KbWVhbihkYXRhc2V0JGNsb3NlKQ0KYGBgDQoNCg0KKip2YXJpYW5jZSBDb2RlKioNCg0KVGhlIGNvbmNlcHQgb2YgdmFyaWFuY2UgaW4gdGhlIGNvbnRleHQgb2YgY2xvc2luZyBwcmljZXMgZm9yIHN0b2NrDQpwcmVkaWN0aW9uIHNlcnZlcyB0byBxdWFudGlmeSB0aGUgc3ByZWFkIG9yIGRpc3BlcnNpb24gb2YgdGhlIGNsb3NpbmcNCnByaWNlcyBhcm91bmQgdGhlaXIgbWVhbiBvciBhdmVyYWdlIHZhbHVlLiBJdCBwcm92aWRlcyBhIG1lYXN1cmUgb2YgaG93DQptdWNoIHRoZSBhY3R1YWwgY2xvc2luZyBwcmljZXMgZGV2aWF0ZSBmcm9tIHRoZSBhdmVyYWdlIGNsb3NpbmcgcHJpY2UNCm92ZXIgYSBzcGVjaWZpYyBwZXJpb2QuDQoNCmBgYHtyfQ0KdmFyKGRhdGFzZXQkY2xvc2UpDQpgYGANCg0KDQotICAgKipTdGF0aXNjYWwgc3VtbWFyaXNlKioNCg0KU3VtbWFyaWVzIGZvciBhbGwgbnVtZXJpYyBhdHRyaWJ1dGVzIGFuZCB0aGVpciBvdXRsaWVycyBhbmQgYm94cGxvdHMuDQoNCmBgYHtyfQ0KI3N0YXN0aXN0aWNhbCBtZWFzdXJlcw0KI3N1bW1hcmllcw0Kc3VtbWFyeShkYXRhc2V0JGNsb3NlKQ0Kc3VtbWFyeShkYXRhc2V0JGhpZ2gpDQpzdW1tYXJ5KGRhdGFzZXQkbG93KQ0Kc3VtbWFyeShkYXRhc2V0JG9wZW4pDQpzdW1tYXJ5KGRhdGFzZXQkdm9sdW1lKQ0Kc3VtbWFyeShkYXRhc2V0JGFkakNsb3NlKQ0Kc3VtbWFyeShkYXRhc2V0JGFkakhpZ2gpDQpzdW1tYXJ5KGRhdGFzZXQkYWRqTG93KQ0Kc3VtbWFyeShkYXRhc2V0JGFkak9wZW4pDQpzdW1tYXJ5KGRhdGFzZXQkYWRqVm9sdW1lKQ0KYGBgDQoNCg0KLSAgICoqT3V0bGllcnMqKg0KDQpgYGB7cn0NCiNvdXRsaWVycw0KYm94cGxvdC5zdGF0cyhkYXRhc2V0JGNsb3NlKSRvdXQNCmJveHBsb3Quc3RhdHMoZGF0YXNldCRoaWdoKSRvdXQNCmJveHBsb3Quc3RhdHMoZGF0YXNldCRsb3cpJG91dA0KYm94cGxvdC5zdGF0cyhkYXRhc2V0JG9wZW4pJG91dA0KYm94cGxvdC5zdGF0cyhkYXRhc2V0JHZvbHVtZSkkb3V0DQpib3hwbG90LnN0YXRzKGRhdGFzZXQkYWRqQ2xvc2UpJG91dA0KYm94cGxvdC5zdGF0cyhkYXRhc2V0JGFkakhpZ2gpJG91dA0KYm94cGxvdC5zdGF0cyhkYXRhc2V0JGFkakxvdykkb3V0DQpib3hwbG90LnN0YXRzKGRhdGFzZXQkYWRqT3Blbikkb3V0DQpib3hwbG90LnN0YXRzKGRhdGFzZXQkYWRqVm9sdW1lKSRvdXQNCmBgYA0KDQoNCi0gICAqKkJveHBsb3RzKioNCg0KYGBge3J9DQojYm94cGxvdHMNCmJveHBsb3QoZGF0YXNldCRjbG9zZSkNCmJveHBsb3QoZGF0YXNldCRoaWdoKQ0KYm94cGxvdChkYXRhc2V0JGxvdykNCmJveHBsb3QoZGF0YXNldCRvcGVuKQ0KYm94cGxvdChkYXRhc2V0JHZvbHVtZSkNCmJveHBsb3QoZGF0YXNldCRhZGpDbG9zZSkNCmJveHBsb3QoZGF0YXNldCRhZGpIaWdoKQ0KYm94cGxvdChkYXRhc2V0JGFkakxvdykNCmJveHBsb3QoZGF0YXNldCRhZGpPcGVuKQ0KYm94cGxvdChkYXRhc2V0JGFkalZvbHVtZSkNCmBgYA0KDQoNCi0gCSoqUGxvdHRpbmcgbWV0aG9kcyoqDQoNCg0KLSAgICoqU2NhdHRlciBQbG90KioNCg0KVGhpcyBzY2F0dGVyIHBsb3QgaGVscHMgdXMgdG8gZGV0ZXJtaW5lIHdoZXRoZXIgdGhlIGNsb3NpbmcgcHJpY2UgYW5kDQp2b2x1bWUgYXJlIGNvcnJlbGF0ZWQgdG8gZWFjaCBvdGhlciBvciBub3QsIGl0IHNob3dzIHRoYXQgdGhlIHR3bw0KYXR0cmlidXRlcyBhcmUgY29yZWxhdGVkIGFuZCBoYXZlIHByb3BvcnRpb25hbCByZWxhdGlvbnNoaXAuDQoNCmBgYHtyfQ0Kd2l0aChkYXRhc2V0LCBwbG90KHZvbHVtZSwgY2xvc2UpKQ0KYGBgDQoNCg0KLSAgICoqQmFycGxvdCoqDQoNClRoZSBCYXIgcGxvdCByZXByZXNlbnRzIHRoZSBjbG9zaW5nIHByaWNlIGFuZCBkYXRlIGluIGRhdGFzZXQuIEl0IGluZGljYXRlcyB0aGF0IGNsb3NpbmcgcHJpY2VzIGF0IHRoZSBlbmQgb2YgYSB0cmFkZWQgZGF5IGFyZSBpbmNyZWFzaW5nIG9yIGRlY3JlYXNpbmcgZGVwZW5kaW5nIG9uIHRoZSBkYXRlLg0KDQpgYGB7cn0NCmJhcnBsb3QoaGVpZ2h0ID0gZGF0YXNldCRjbG9zZSwgbmFtZXMuYXJnID0gZGF0YXNldCRkYXRlLCB4bGFiID0gIkRhdGUiLCB5bGFiID0gIkNsb3NpbmcgcHJpY2UiLCBtYWluID0gImRhdGUgdnMgQ2xvc2UiKQ0KYGBgDQoNCg0KLSAgICoqSGlzdG9ncmFtKioNCg0KVGhpcyBIaXN0b2dyYW0gcmVwcmVzZW50cyB0aGUgZnJlcXVlbmN5IG9mIGEgc3RvY2sgY2xvc2luZyBwcmljZSBpbiB0aGUgZGF0YXNldC4gQWZ0ZXIgb2JzZXJ2YXRpb24sIHdlIG5vdGljZWQgdGhhdCB0aGUgbW9zdCB2YWx1ZXMgbGllIGluIGJldHdlZW4gMTAwMCB0byAxMjAwLg0KDQpgYGB7cn0NCmhpc3QoZGF0YXNldCRjbG9zZSkNCmBgYA0KDQoNCiMgIDQuICBEYXRhIHByZXByb2Nlc3NpbmcNCg0KDQotICAgKipSYXcgZGF0YXNldCoqDQoNCkhlcmUgaXMgb3VyIGRhdGEgc2V0IGJlZm9yZSBwcmVwcm9jZXNzaW5nDQoNCmBgYHtyfQ0KI2RhdGFzZXQgYmVmb3JlIHByZXByb2Nlc3NpbmcNCnByaW50KGRhdGFzZXQpDQpgYGANCg0KDQotICAgICoqQ2hlY2tpbmcgZm9yIG1pc3NpbmcgdmFsdWVzKioNCg0KRGF0YSBjbGVhbmluZywgaW5jbHVkaW5nIGhhbmRsaW5nIG1pc3NpbmcgdmFsdWVzIGxpa2UgTlVMTHMsIGlzIGNydWNpYWwgYmVmb3JlIHV0aWxpemluZyBkYXRhIGZvciBhbmFseXNpcyBvciBtb2RlbGluZy4gSXTigJlzIGltcG9ydGFudCB0byBnZXQgdGhlIGJlc3QgcXVhbGl0eSBvZiBhbmFseXNpcy4gU3VjaCBhcyBhY2N1cmFjeSB3aGVyZSBtaXNzaW5nIG9yIGluY29ycmVjdCBkYXRhIGNhbiBza2V3IGFuYWx5c2lzLCBsZWFkaW5nIHRvIGluYWNjdXJhdGUgaW5zaWdodHMgb3IgcHJlZGljdGlvbnMuIEFuZCBjbGVhbiBkYXRhIGVuc3VyZXMgdGhlIHJlbGlhYmlsaXR5IG9mIHlvdXIgZmluZGluZ3MsIHJlZHVjaW5nIHRoZSByaXNrIG9mIG1ha2luZyBkZWNpc2lvbnMgYmFzZWQgb24gZmxhd2VkIGluZm9ybWF0aW9uLg0KDQoqdG8gZmluZCB0aGUgdG90YWwgbnVsbCB2YWx1ZXMgaW4gdGhlIGRhdGFzZXQgI0NoZWNraW5nIE5VTEwsIEZBTFNFDQptZWFucyBubyBudWxsLCBUUlVFIGNlbGxzIG1lYW5zIHRoZSB2YWx1ZSBvZiB0aGUgY2VsbCBpcyBudWxsKg0KDQpgYGB7cn0NCmlzLm5hKGRhdGFzZXQpDQpzdW0oaXMubmEoZGF0YXNldCkpDQoNCnByaW50KCJTaW5jZSB0aGVyZSBpcyBubyBOVUxMIHZhbHVlcyB3ZSBkb24ndCBuZWVkIHRvIHJlbW92ZSBhbnkgcm93cyIpDQpgYGANCg0KSW4gb3VyIGRhdGEgc2luY2UgdGhlcmUgYXJlIG5vIE51bGwgdmFsdWVzLCB3ZSBkb27igJl0IG5lZWQgdG8gcmVtb3ZlIGFueSByb3dzLg0KDQoNCi0gICAgKipEZXRlY3RpbmcgYW5kIHJlbW92aW5nIHRoZSBvdXRsaWVycyoqDQoNClNpbmNlIG1vc3QgYXR0cmlidXRlcyBpbiBvdXIgZGF0YXNldCBhcmUgbnVtZXJpYyBhbmQgcmVtb3Zpbmcgb3V0bGllcnMgd2lsbCBhZmZlY3Qgb3VyIGNhbGN1bGF0aW9ucyBhbmQgcHJlZGljdGlvbiwgd2Ugd2lsbCByZW1vdmUgY2xvc2luZyBwcmljZSBhbmQgdm9sdW1lcyBvdXRsaWVycyBvbmx5Lg0KDQpgYGB7cn0NCiNkYXRhc2V0IGJlZm9yZSByZW1vdmluZyBvdXRsaWVycw0KcHJpbnQoZGF0YXNldCkNCnN1bW1hcnkoZGF0YXNldCkNCnN0cihkYXRhc2V0KQ0KDQojcmVtb3ZpbmcgY2xvc2Ugb3V0bGllcg0Kb3V0bGllcnMgPC0gYm94cGxvdChkYXRhc2V0JGNsb3NlLCBwbG90PUZBTFNFKSRvdXQNCmRhdGFzZXQgPC0gZGF0YXNldFstd2hpY2goZGF0YXNldCRjbG9zZSAlaW4lIG91dGxpZXJzKSxdDQpib3hwbG90LnN0YXRzKGRhdGFzZXQkY2xvc2UpJG91dA0KDQojcmVtb3Zpbmcgdm9sdW1lJ3Mgb3V0bGllcg0Kb3V0bGllcnMgPC0gYm94cGxvdChkYXRhc2V0JHZvbHVtZSwgcGxvdD1GQUxTRSkkb3V0DQpkYXRhc2V0IDwtIGRhdGFzZXRbLXdoaWNoKGRhdGFzZXQkdm9sdW1lICVpbiUgb3V0bGllcnMpLF0NCmJveHBsb3Quc3RhdHMoZGF0YXNldCR2b2x1bWUpJG91dA0KDQojZGF0YSBzZXQgYWZ0ZXIgcmVtb3Zpbmcgb3V0bGllcnMNCnByaW50KGRhdGFzZXQpDQpzdW1tYXJ5KGRhdGFzZXQpDQpzdHIoZGF0YXNldCkNCmBgYA0KDQoNCg0KLSAgICoqRGF0YSB0cmFuc2Zvcm1hdGlvbioqDQoNCioqRmVhdHVyZSBzZWxlY3Rpb24qKg0KDQpSZW1vdmUgUmVkdW5kYW50IEZlYXR1cmVzDQoNCmBgYHtyfQ0KIyBsb2FkIHRoZSBsaWJyYXJ5ICAgICAgICANCmxpYnJhcnkobWxiZW5jaCkNCmxpYnJhcnkoY2FyZXQpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGxhdHRpY2UpDQoNCiMgY2FsY3VsYXRlIGNvcnJlbGF0aW9uIG1hdHJpeA0KY29ycmVsYXRpb25NYXRyaXggPC0gY29yKGRhdGFzZXRbLDI6MTFdKQ0KDQojIHN1bW1hcml6ZSB0aGUgY29ycmVsYXRpb24gbWF0cml4DQpwcmludChjb3JyZWxhdGlvbk1hdHJpeCkNCg0KIyBmaW5kIGF0dHJpYnV0ZXMgdGhhdCBhcmUgaGlnaGx5IGNvcnJlY3RlZCAoaWRlYWxseSA+MC43NSkNCmhpZ2hseUNvcnJlbGF0ZWQgPC0gZmluZENvcnJlbGF0aW9uKGNvcnJlbGF0aW9uTWF0cml4LCBjdXRvZmY9MC41ICkNCg0KIyBwcmludCBpbmRleGVzIG9mIGhpZ2hseSBjb3JyZWxhdGVkIGF0dHJpYnV0ZXMNCnByaW50KGhpZ2hseUNvcnJlbGF0ZWQpDQpgYGANCg0KDQotICAgKipOb3JtYWxpemF0aW9uKioNCg0KDQpkYXRhc2V0IGJlZm9yZSBub3JtYWxpemF0aW9uIA0KDQpgYGB7cn0NCiNkYXRhc2V0IGJlZm9yZSBub3JtYWxpemF0aW9uIA0KcHJpbnQoZGF0YXNldCkNCnN1bW1hcnkoZGF0YXNldCkNCnN0cihkYXRhc2V0KQ0KYGBgDQoNCg0Kbm9ybWFsaXphdGlvbiB3YXMgcGVyZm9ybWVkIHRvIGVuc3VyZSBjb25zaXN0ZW50IHNjYWxpbmcgb2YgdGhlIGRhdGEuDQpUaGUgbm9ybWFsaXphdGlvbiB0ZWNobmlxdWUgYXBwbGllZCB3YXMgdGhlIG1heC1taW4gbm9ybWFsaXphdGlvbi4gVGhpcw0KdGVjaG5pcXVlIHJlc2NhbGVzIHRoZSB2YWx1ZXMgb2Ygc3BlY2lmaWMgYXR0cmlidXRlcyB3aXRoaW4gYSBkZWZpbmVkDQpyYW5nZSBiZXR3ZWVuIDAgYW5kIDEuDQoNCldlIGNhbiB1c2UgdGhlIG5vcm1hbGl6ZWQgZGF0YXNldCBwcm92aWRlcyBhIG1vcmUgdW5pZm9ybSBhbmQgY29tcGFyYWJsZQ0KcmVwcmVzZW50YXRpb24gb2YgdGhlIGF0dHJpYnV0ZXMsIGVuYWJsaW5nIGFjY3VyYXRlIGFuYWx5c2lzIGFuZA0KbW9kZWxpbmcgZm9yIHN0b2NrIHByZWRhY3Rpb24gd2l0aCByZXN1bHQgYXMgc2hvd24uDQoNCmBgYHtyfQ0Kbm9ybWFsaXplIDwtIGZ1bmN0aW9uKHgpIHtyZXR1cm4gKCh4IC0gbWluKHgpKSAvIChtYXgoeCkgLSBtaW4oeCkpKX0NCmRhdGFXaXRob3V0Tm9ybWFsaXphdGlvbiA8LSBkYXRhc2V0DQpkYXRhc2V0JGNsb3NlPC1ub3JtYWxpemUoZGF0YVdpdGhvdXROb3JtYWxpemF0aW9uJGNsb3NlKQ0KZGF0YXNldCR2b2x1bWU8LW5vcm1hbGl6ZShkYXRhV2l0aG91dE5vcm1hbGl6YXRpb24kdm9sdW1lKQ0KZGF0YXNldCRvcGVuPC1ub3JtYWxpemUoZGF0YVdpdGhvdXROb3JtYWxpemF0aW9uJG9wZW4pDQpkYXRhc2V0JGxvdyA8LW5vcm1hbGl6ZShkYXRhV2l0aG91dE5vcm1hbGl6YXRpb24kbG93KQ0KZGF0YXNldCRoaWdoIDwtbm9ybWFsaXplKGRhdGFXaXRob3V0Tm9ybWFsaXphdGlvbiRoaWdoKQ0KYGBgDQoNCg0KZGF0YXNldCBhZnRlciBub3JtYWxpemF0aW9uDQoNCmBgYHtyfQ0KI2RhdGFzZXQgYWZ0ZXIgbm9ybWFsaXphdGlvbiANCnByaW50KGRhdGFzZXQpDQpzdW1tYXJ5KGRhdGFzZXQpDQpzdHIoZGF0YXNldCkNCmBgYA0KDQoNCi0gICAqKkRpc2NyZXRpemF0aW9uKioNCg0KDQpkYXRhc2V0IGJlZm9yZSBEaXNjcmV0aXphdGlvbiANCg0KYGBge3J9DQojZGF0YXNldCBiZWZvcmUgRGlzY3JldGl6YXRpb24gDQpwcmludChkYXRhc2V0KQ0Kc3VtbWFyeShkYXRhc2V0KQ0Kc3RyKGRhdGFzZXQpDQpgYGANCg0KDQp3ZSB1c2VkIHRoZSBEaXNjcmV0aXphdGlvbiB0ZWNobmlxdWUgb24gb3VyIGNsYXNzIGxhYmVsICJjbG9zZSIgdG8NCnNpbXBsaWZ5IGl0IGFzIGl0IGhhcyBhIGxhcmdlIGNvbnRpbnVvdXMgdmFsdWVzLCB3ZSBtYWRlIHRoZW0gZmFsbCBpbnRvDQppbnRlcnZhbHMsIHRvIG1ha2UgaXQgZWFzaWVyIHRvIGFuYWx5emUNCg0KYW5kIHdlIGNob3NlIHRoZSB2YWx1ZSAwLjI5NTcyNTEgYXMgaXQgdGhlIG1lYW4gdmFsdWUgZm9yIHRoZSBjbG9zaW5nDQoNCmBgYHtyfQ0KZGF0YXNldCRjbG9zZSA8LSBpZmVsc2UoZGF0YXNldCRjbG9zZSA8PSAwLjI5NTcyNTEgLCAibG93IiwiSGlnaCIpDQpwcmludChkYXRhc2V0KQ0KYGBgDQoNCndlIGRpc2NyZXRpemVkIGl0IGludG8gdHdvIGNhdGVnb3JpZXMgKGxvdywgaGlnaCkgYmFzZWQgb24gdGhlIG1hZW4sIGxvdw0KbWVhbmluZyBpdCBpcyBsZXNzIHRoYW4gdGhlIG1lYW4gb2YgdGhlIGNsb3NlICwgYW5kIGhpZ2ggbWVhbmluZyBpdCBpcw0KZXF1YWwgdG8gb3IgaGlnaGVyIHRoYW4gdGhlIG1lYW4uDQoNCg0KRW5jb2RpbmcgDQpXZSBlbmNvZGVkIGNsb3NlIGRhdGEgaW50byBmYWN0b3JzLCB3aGljaCB3b3VsZCBoZWxwIHRoZSBtb2RlbCByZWFkIHRoaXMgZGF0YSBlYXNpbHkNCg0KYGBge3J9DQoNCmRhdGFzZXQkY2xvc2UgPC0gZmFjdG9yKGRhdGFzZXQkY2xvc2UsbGV2ZWxzID0gYygibG93IiwgIkhpZ2giKSwgbGFiZWxzID0gYygiMSIsICIyIikpDQoNCnByaW50KGRhdGFzZXQpDQpgYGANCg0KDQpkYXRhc2V0IGFmdGVyIERpc2NyZXRpemF0aW9uDQoNCmBgYHtyfQ0KI2RhdGFzZXQgYWZ0ZXIgRGlzY3JldGl6YXRpb24gDQpwcmludChkYXRhc2V0KQ0Kc3VtbWFyeShkYXRhc2V0KQ0Kc3RyKGRhdGFzZXQpDQpgYGANCg0KDQpzdW1tYXJ5IGFmdGVyIHByZXByb2Nlc3NpbmcgYWZ0ZXIgcHJlcHJvY2Vzc2luZyB0aGUgZGF0YSBmb3Igc3RvY2sNCnByaWNlIHByZWRpY3Rpb24sIHNldmVyYWwgc3RlcHMgYXJlIHRha2VuIHRvIHJlZmluZSwgY2xlYW4sIGFuZCBwcmVwYXJlDQp0aGUgZGF0YSBmb3IgYW5hbHlzaXMgYW5kIG1vZGVsaW5nLiBUaGVzZSBwcmVwcm9jZXNzaW5nIHN0ZXBzIGFpbSB0bw0KZW5oYW5jZSB0aGUgcXVhbGl0eSBhbmQgcmVsaWFiaWxpdHkgb2YgdGhlIGRhdGEgZm9yIG1vcmUgYWNjdXJhdGUgc3RvY2sNCnByaWNlIHByZWRpY3Rpb24uDQoNCmRhdGFzZXQgYWZ0ZXIgcHJlcHJvY2Vzc2luZw0KDQpgYGB7cn0NCiNkYXRhc2V0IGFmdGVyIHByZXByb2Nlc3NpbmcgDQpwcmludChkYXRhc2V0KQ0Kc3VtbWFyeShkYXRhc2V0KQ0Kc3RyKGRhdGFzZXQpDQpgYGANCg0KDQoqKkZlYXR1cmUgc2VsZWN0aW9uKioNCg0KRmVhdHVyZSBzZWxlY3Rpb24gaXMgYSBwcm9jZXNzIG9mIHNlbGVjdGluZyBhIHN1YnNldCBvZiByZWxldmFudA0KZmVhdHVyZXMgKG9yIGF0dHJpYnV0ZXMpIGZyb20gdGhlIG9yaWdpbmFsIHNldCBvZiBmZWF0dXJlcyBpbiBhIGRhdGFzZXQuDQpUaGUgZ29hbCBvZiBmZWF0dXJlIHNlbGVjdGlvbiBpcyB0byBjaG9vc2UgdGhlIG1vc3QgcmVsZXZhbnQgYW5kDQppbXBvcnRhbnQgZmVhdHVyZXMsIHRoZXJlYnkgcmVkdWNpbmcgZGltZW5zaW9uYWxpdHksIGFuZCBpbXByb3ZpbmcgbW9kZWwNCnBlcmZvcm1hbmNlLg0KDQojRmVhdHVyZSBzZWxlY3Rpb24gLEZlYXR1cmUgc2VsZWN0aW9uIHVzaW5nIFJlY3Vyc2l2ZSBGZWF0dXJlDQpFbGltaW5hdGlvbiBvciBSRkUNCg0KYGBge3J9DQogICAgbGlicmFyeShtbGJlbmNoKQ0KbGlicmFyeShjYXJldCkNCg0KIyBkZWZpbmUgdGhlIGNvbnRyb2wgdXNpbmcgYSByYW5kb20gZm9yZXN0IHNlbGVjdGlvbiBmdW5jdGlvbiANCiMgbnVtYmVyPTEyIG1lYW5zIHRoZSBsZW5ndGggb2YgdGhlIGxpc3QNCmNvbnRyb2wgPC0gcmZlQ29udHJvbChmdW5jdGlvbnM9cmZGdW5jcywgbWV0aG9kPSJjdiIsIG51bWJlcj0xMSkNCiMgcnVuIHRoZSBSRkUgYWxnb3JpdGhtIGZyb20gY29sdW1uIDEgdG8gMTEgIA0KcmVzdWx0cyA8LSByZmUoZGF0YXNldFssMToxMF0sZGF0YXNldFssMTFdLCBzaXplcz1jKDE6MTApLCByZmVDb250cm9sPWNvbnRyb2wpDQpgYGANCg0Kc3VtbWFyaXplIHRoZSByZXN1bHRzDQoNCmBgYHtyfQ0KcHJpbnQocmVzdWx0cykNCmBgYA0KDQpsaXN0IHRoZSBjaG9zZW4gZmVhdHVyZXMNCg0KYGBge3J9DQpwcmVkaWN0b3JzKHJlc3VsdHMpDQpgYGANCg0KcGxvdCB0aGUgcmVzdWx0cw0KDQpgYGB7cn0NCnBsb3QocmVzdWx0cywgdHlwZT1jKCJoIiwgIm8iKSkNCmBgYA0KDQoNCiMgIDUuICAgRGF0YSBNaW5pbmcgVGVjaG5pcXVlcw0KDQpXZSBkaWQgYm90aCBzdXBlcnZpc2VkIGFuZCB1bnN1cGVydmlzZWQgbGVhcm5pbmcgdGVjaG5pcXVlcyBvbiBvdXINCmRhdGFzZXQgKEdvb2dsZSBzdG9jayBwcmVkaWN0aW9uKSwgd2hpY2ggaW52b2x2ZXMgY2xhc3NpZmljYXRpb24gYW5kDQpjbHVzdGVyaW5nIG1ldGhvZHMsIGZvciBjbGFzc2lmaWNhdGlvbiB3ZSBkaWQgYSBwYXJ0aXRpb25pbmcgbWV0aG9kDQpjYWxsZWQgdGhlIHRyYWluLXRlc3Qgc3BsaXQsIHdoaWNoIHNwbGl0cyB0aGUgZGF0YXNldCBpbnRvIHR3byBzdWJzZXRzDQpvZiBkaWZmZXJlbnQgcmF0aW9zLCBhbmQgd2UgaW1wbGVtZW50ZWQgdGhyZWUgYWxnb3JpdGhtcyB0byBmb3JtIDkNCmRpZmZlcmVudCBkZWNpc2lvbiB0cmVlcy4NCg0KDQoNCiMgIDYuICAgRXZhbHVhdGlvbiBhbmQgQ29tcGFyaXNvbg0KDQoNCi0gICAqKkNsYXNzaWZpY2F0aW9uKioNCg0KV2Ugd2lsbCBjaG9vc2UgdGhlIGF0dHJpYnV0ZXMgd2l0aCB0aGUgaGlnaGVzdCBpbXBvcnRhbmNlIChmcm9tIGZlYXR1cmUNCnNlbGVjdGlvbikgdG8gY3JlYXRlIGEgdHJlZToNCg0KDQoxLiBEaXZpZGluZyB0aGUgZGF0YXNldDoNCg0Kd2UgZGl2aWRlZCBvdXIgZGF0YXNldCBpbnRvIHR3byBkaXZpc2lvbnMgZm9yIGVhY2ggc3BsaXQ6DQoNCmZpcnN0IG9uZSA3MC0zMCwgd2hpY2ggbWVhbnMgVHJhaW5pbmcoNzAlKSBhbmQgVGVzdGluZygzMCUpOg0KDQpgYGB7cn0NCiMgYSBmaXhlZCByYW5kb20gc2VlZCB0byBtYWtlIHJlc3VsdHMgcmVwcm9kdWNpYmxlDQpzZXQuc2VlZCgxMjM0KQ0KDQojIDEuU3BsaXQgdGhlIGRhdGFzZXRzIGludG8gdHdvIHN1YnNldHM6IFRyYWluaW5nKDcwJSkgYW5kIFRlc3RpbmcoMzAlKToNCmluZDEgPC0gc2FtcGxlKDIsIG5yb3coZGF0YXNldCksIHJlcGxhY2U9VFJVRSwgcHJvYj1jKCAwLjcwLCAwLjMwKSkNCnRyYWluRGF0YSAgPC0gZGF0YXNldFtpbmQxPT0xLF0NCnRlc3REYXRhIDwtIGRhdGFzZXRbaW5kMT09MixdDQpgYGANCg0KDQoyLiBEZXRlcm1pbmUgdGhlIHByZWRpY3RvciBhdHRyaWJ1dGVzIGFuZCB0aGUgY2xhc3MgbGFiZWwgYXR0cmlidXRlLiggdGhlIGZvcm11bGEpOg0KDQpgYGB7cn0NCmxpYnJhcnkocGFydHkpICAgIA0KI215Rm9ybXVsYSANCm15Rm9ybXVsYSA8LSBjbG9zZSB+dm9sdW1lK29wZW4raGlnaCtsb3cNCg0KYGBgDQoNCg0KMS4gQnVpbGQgYSBkZWNpc2lvbiB0cmVlIHVzaW5nIEluZm9ybWF0aW9uIGdhaW46DQoNCkluZm9ybWF0aW9uIGdhaW4gaXMgYSBjb25jZXB0IHVzZWQgaW4gdGhlIGZpZWxkIG9mIG1hY2hpbmUgbGVhcm5pbmcgYW5kDQpkZWNpc2lvbiB0cmVlIGFsZ29yaXRobXMuIEl0IGlzIGEgbWVhc3VyZSBvZiB0aGUgZWZmZWN0aXZlbmVzcyBvZiBhDQpwYXJ0aWN1bGFyIGF0dHJpYnV0ZSBpbiBjbGFzc2lmeWluZyBkYXRhLiBJbiB0aGUgY29udGV4dCBvZiBkZWNpc2lvbg0KdHJlZXMsIGluZm9ybWF0aW9uIGdhaW4gaGVscHMgZGV0ZXJtaW5lIHRoZSBvcmRlciBpbiB3aGljaCBhdHRyaWJ1dGVzDQphcmUgY2hvc2VuIGZvciBzcGxpdHRpbmcgdGhlIGRhdGEuDQoNCmBgYHtyfQ0KZGF0YXNldF9jdHJlZSA8LSBjdHJlZShteUZvcm11bGEsIGRhdGE9dHJhaW5EYXRhKQ0KdGFibGUocHJlZGljdChkYXRhc2V0X2N0cmVlKSwgdHJhaW5EYXRhJGNsb3NlKQ0KIyA0LlByaW50IGFuZCBwbG90IHRoZSB0cmVlOg0KDQpwcmludChkYXRhc2V0X2N0cmVlKQ0KcGxvdChkYXRhc2V0X2N0cmVlLCB0eXBlPSJzaW1wbGUiKQ0KYGBgDQoNCmBgYHtyfQ0KIyA1LlVzZSB0aGUgY29uc3RydWN0ZWQgbW9kZWwgdG8gcHJlZGljdCB0aGUgY2xhc3MgbGFiZWxzIG9mIHRlc3QgZGF0YToNCnRlc3RQcmVkIDwtIHByZWRpY3QoZGF0YXNldF9jdHJlZSwgbmV3ZGF0YSA9IHRlc3REYXRhKQ0KcmVzdWx0PC10YWJsZSh0ZXN0UHJlZCwgdGVzdERhdGEkY2xvc2UpDQpyZXN1bHQNCmBgYA0KDQpgYGB7cn0NCiMgRXZhbHVhdGUgdGhlIG1vZGVsIGFuZCBjcmVhdGUgY29uZnVzaW9uIG1hdHJpeA0KaW5zdGFsbC5wYWNrYWdlcygiY2FyZXQiKQ0KaW5zdGFsbC5wYWNrYWdlcygnZTEwNzEnLCBkZXBlbmRlbmNpZXM9VFJVRSkNCmxpYnJhcnkoZTEwNzEpDQpsaWJyYXJ5KGNhcmV0KQ0KDQpjb19yZXN1bHQgPC0gY29uZnVzaW9uTWF0cml4KHJlc3VsdCkNCg0KcHJpbnQoY29fcmVzdWx0KQ0Kc2Vuc2l0aXZpdHkoYXMudGFibGUoY29fcmVzdWx0KSkNCnNwZWNpZmljaXR5KGFzLnRhYmxlKGNvX3Jlc3VsdCkpDQpwcmVjaXNpb24oYXMudGFibGUoY29fcmVzdWx0KSkNCg0KYWNjIDwtIGNvX3Jlc3VsdCRvdmVyYWxsWyJBY2N1cmFjeSJdDQphY2MNCmBgYA0KDQoNCjIuIEJ1aWxkaW5nIHRoZSBUcmVlIHVzaW5nIEdpbmkgSW5kZXgoQ0FSVCkNCg0KVGhlIEdpbmkgSW5kZXggaXMgYW5vdGhlciBjcml0ZXJpb24gdXNlZCBpbiBkZWNpc2lvbiB0cmVlIGFsZ29yaXRobXMsDQpwYXJ0aWN1bGFybHkgaW4gdGhlIGNvbnRleHQgb2YgdGhlIENsYXNzaWZpY2F0aW9uIGFuZCBSZWdyZXNzaW9uIFRyZWVzDQooQ0FSVCkgYWxnb3JpdGhtLiBMaWtlIGluZm9ybWF0aW9uIGdhaW4sIHRoZSBHaW5pIEluZGV4IGlzIHVzZWQgdG8NCmV2YWx1YXRlIHRoZSBpbXB1cml0eSBvciBob21vZ2VuZWl0eSBvZiBhIGRhdGFzZXQuDQoNClRoZSBHaW5pIEluZGV4IGZvciBhIHNwZWNpZmljIGF0dHJpYnV0ZSBtZWFzdXJlcyB0aGUgcHJvYmFiaWxpdHkgb2YNCmluY29ycmVjdGx5IGNsYXNzaWZ5aW5nIGEgcmFuZG9tbHkgY2hvc2VuIGVsZW1lbnQgaW4gdGhlIGRhdGFzZXQuIEENCmxvd2VyIEdpbmkgSW5kZXggaW5kaWNhdGVzIGEgcHVyZXIgb3IgbW9yZSBob21vZ2VuZW91cyBzZXQuIEluIHRoZQ0KY29udGV4dCBvZiBkZWNpc2lvbiB0cmVlcywgdGhlIGF0dHJpYnV0ZSB3aXRoIHRoZSBsb3dlc3QgR2luaSBJbmRleCBpcw0KY2hvc2VuIGFzIHRoZSBzcGxpdCBhdHRyaWJ1dGUuDQoNCmBgYHtyfQ0KIyBGb3IgZGVjaXNpb24gdHJlZSBtb2RlbA0KaW5zdGFsbC5wYWNrYWdlcygicnBhcnQiKQ0KbGlicmFyeShycGFydCkNCiMgRm9yIGRhdGEgdmlzdWFsaXphdGlvbg0KbGlicmFyeShycGFydC5wbG90KQ0KDQpkYXRhc2V0LmNhcnQgPC0gcnBhcnQobXlGb3JtdWxhLCBkYXRhID0gdHJhaW5EYXRhLCBtZXRob2QgPSAiY2xhc3MiLCBwYXJtcyA9IGxpc3Qoc3BsaXQgPSAiZ2luaSIpKQ0KYGBgDQoNCg0KVmlzdWFsaXppbmcgdGhlIHVucHJ1bmVkIHRyZWUNCg0KYGBge3J9DQpsaWJyYXJ5KHJwYXJ0LnBsb3QpDQpycGFydC5wbG90KGRhdGFzZXQuY2FydCkNCmBgYA0KDQoNCkNoZWNraW5nIHRoZSBvcmRlciBvZiB2YXJpYWJsZSBpbXBvcnRhbmNlDQoNCmBgYHtyfQ0KZGF0YXNldC5jYXJ0JHZhcmlhYmxlLmltcG9ydGFuY2UNCnByZWQudHJlZSA9IHByZWRpY3QoZGF0YXNldC5jYXJ0LCB0ZXN0RGF0YSwgdHlwZSA9ICJjbGFzcyIpDQoNCnRhYmxlKHByZWQudHJlZSx0ZXN0RGF0YSRjbG9zZSkNCmBgYA0KDQpgYGB7cn0NCiMgNS5Vc2UgdGhlIGNvbnN0cnVjdGVkIG1vZGVsIHRvIHByZWRpY3QgdGhlIGNsYXNzIGxhYmVscyBvZiB0ZXN0IGRhdGE6DQp0ZXN0UHJlZCA8LSBwcmVkaWN0KGRhdGFzZXRfY3RyZWUsIG5ld2RhdGEgPSB0ZXN0RGF0YSkNCnJlc3VsdDwtdGFibGUodGVzdFByZWQsIHRlc3REYXRhJGNsb3NlKQ0KcmVzdWx0DQpgYGANCg0KYGBge3J9DQojIEV2YWx1YXRlIHRoZSBtb2RlbCBhbmQgY3JlYXRlIGNvbmZ1c2lvbiBtYXRyaXgNCmluc3RhbGwucGFja2FnZXMoImNhcmV0IikNCmluc3RhbGwucGFja2FnZXMoJ2UxMDcxJywgZGVwZW5kZW5jaWVzPVRSVUUpDQpsaWJyYXJ5KGUxMDcxKQ0KbGlicmFyeShjYXJldCkNCg0KY29fcmVzdWx0IDwtIGNvbmZ1c2lvbk1hdHJpeChyZXN1bHQpDQoNCnByaW50KGNvX3Jlc3VsdCkNCnNlbnNpdGl2aXR5KGFzLnRhYmxlKGNvX3Jlc3VsdCkpDQpzcGVjaWZpY2l0eShhcy50YWJsZShjb19yZXN1bHQpKQ0KcHJlY2lzaW9uKGFzLnRhYmxlKGNvX3Jlc3VsdCkpDQoNCmFjYyA8LSBjb19yZXN1bHQkb3ZlcmFsbFsiQWNjdXJhY3kiXQ0KYWNjDQpgYGANCg0KDQozLiBCdWlsZGluZyB0aGUgVHJlZSB1c2luZyBHYWluIHJhdGlvKEM1KQ0KDQpUaGUgR2FpbiBSYXRpbyBpcyB1c2VkIHRvIHNlbGVjdCB0aGUgYXR0cmlidXRlIHRoYXQgbWF4aW1pemVzIHRoZQ0KSW5mb3JtYXRpb24gR2FpbiB3aGlsZSBhdm9pZGluZyB0aGUgYmlhcyB0b3dhcmRzIGF0dHJpYnV0ZXMgd2l0aCBtYW55DQp2YWx1ZXMuIEl0IHByb3ZpZGVzIGEgbW9yZSBiYWxhbmNlZCBtZWFzdXJlIGZvciBhdHRyaWJ1dGUgc2VsZWN0aW9uIGluDQpkZWNpc2lvbiB0cmVlIGNvbnN0cnVjdGlvbi4NCg0KV2hpbGUgSW5mb3JtYXRpb24gR2FpbiBzaW1wbHkgbWVhc3VyZXMgdGhlIHJlZHVjdGlvbiBpbiBlbnRyb3B5IG9yDQp1bmNlcnRhaW50eSwgR2FpbiBSYXRpbyB0YWtlcyBpbnRvIGFjY291bnQgdGhlIGludHJpbnNpYyBpbmZvcm1hdGlvbiBvZg0KYW4gYXR0cmlidXRlLiBJdCBhaW1zIHRvIHBlbmFsaXplIGF0dHJpYnV0ZXMgdGhhdCBtYXkgaGF2ZSBhIGxhcmdlDQpudW1iZXIgb2YgdmFsdWVzLCBwb3RlbnRpYWxseSBsZWFkaW5nIHRvIG92ZXJmaXR0aW5nLg0KDQpgYGB7cn0NCmluc3RhbGwucGFja2FnZXMoImNhcmV0IikNCmluc3RhbGwucGFja2FnZXMoIkM1MCIpDQppbnN0YWxsLnBhY2thZ2VzKCJwcmludHIiKQ0KDQpsaWJyYXJ5KEM1MCkNCmxpYnJhcnkocHJpbnRyKQ0KbGlicmFyeShjYXJldCkNCiN0cmFpbiB1c2luZyB0aGUgdHJhaW5EYXRhIGFuZCBjcmVhdGUgdGhlIGM1LjAgZ2FpbiByYXRpbyB0cmVlDQpDbG9zZVRyZWUgPC0gQzUuMChteUZvcm11bGEsIGRhdGE9dHJhaW5EYXRhKQ0Kc3VtbWFyeShDbG9zZVRyZWUpDQpwbG90KENsb3NlVHJlZSkNCmBgYA0KDQoNCnNlY29uZCBvbmUgNjAtNDAsIHdoaWNoIG1lYW5zIFRyYWluaW5nKDYwJSkgYW5kIFRlc3RpbmcoNDAlKToNCg0KYGBge3J9DQojIGEgZml4ZWQgcmFuZG9tIHNlZWQgdG8gbWFrZSByZXN1bHRzIHJlcHJvZHVjaWJsZQ0Kc2V0LnNlZWQoMTIzNCkNCg0KIyAxLlNwbGl0IHRoZSBkYXRhc2V0cyBpbnRvIHR3byBzdWJzZXRzOiBUcmFpbmluZyg2MCUpIGFuZCBUZXN0aW5nKDQwJSk6DQppbmQxIDwtIHNhbXBsZSgyLCBucm93KGRhdGFzZXQpLCByZXBsYWNlPVRSVUUsIHByb2I9YygwLjYwICwgMC40MCkpDQp0cmFpbkRhdGEgIDwtIGRhdGFzZXRbaW5kMT09MSxdDQp0ZXN0RGF0YSA8LSBkYXRhc2V0W2luZDE9PTIsXQ0KYGBgDQoNCg0KMi4gRGV0ZXJtaW5lIHRoZSBwcmVkaWN0b3IgYXR0cmlidXRlcyBhbmQgdGhlIGNsYXNzIGxhYmVsIGF0dHJpYnV0ZS4oIHRoZSBmb3JtdWxhKToNCg0KYGBge3J9DQpsaWJyYXJ5KHBhcnR5KSAgICANCiNteUZvcm11bGEgDQpteUZvcm11bGEgPC0gY2xvc2UgfnZvbHVtZStvcGVuK2hpZ2grbG93DQpgYGANCg0KDQozLiBCdWlsZCBhIGRlY2lzaW9uIHRyZWUgdXNpbmcgdHJhaW5pbmcgc2V0IGFuZCBjaGVjayB0aGUgUHJlZGljdGlvbjoNCg0KYGBge3J9DQpkYXRhc2V0X2N0cmVlIDwtIGN0cmVlKG15Rm9ybXVsYSwgZGF0YT10cmFpbkRhdGEpDQp0YWJsZShwcmVkaWN0KGRhdGFzZXRfY3RyZWUpLCB0cmFpbkRhdGEkY2xvc2UpDQojIDQuUHJpbnQgYW5kIHBsb3QgdGhlIHRyZWU6DQoNCnByaW50KGRhdGFzZXRfY3RyZWUpDQpwbG90KGRhdGFzZXRfY3RyZWUsIHR5cGU9InNpbXBsZSIpDQpgYGANCg0KYGBge3J9DQojIDUuVXNlIHRoZSBjb25zdHJ1Y3RlZCBtb2RlbCB0byBwcmVkaWN0IHRoZSBjbGFzcyBsYWJlbHMgb2YgdGVzdCBkYXRhOg0KdGVzdFByZWQgPC0gcHJlZGljdChkYXRhc2V0X2N0cmVlLCBuZXdkYXRhID0gdGVzdERhdGEpDQpyZXN1bHQ8LXRhYmxlKHRlc3RQcmVkLCB0ZXN0RGF0YSRjbG9zZSkNCnJlc3VsdA0KYGBgDQoNCmBgYHtyfQ0KIyBFdmFsdWF0ZSB0aGUgbW9kZWwgYW5kIGNyZWF0ZSBjb25mdXNpb24gbWF0cml4DQppbnN0YWxsLnBhY2thZ2VzKCJjYXJldCIpDQppbnN0YWxsLnBhY2thZ2VzKCdlMTA3MScsIGRlcGVuZGVuY2llcz1UUlVFKQ0KbGlicmFyeShlMTA3MSkNCmxpYnJhcnkoY2FyZXQpDQoNCmNvX3Jlc3VsdCA8LSBjb25mdXNpb25NYXRyaXgocmVzdWx0KQ0KDQpwcmludChjb19yZXN1bHQpDQpzZW5zaXRpdml0eShhcy50YWJsZShjb19yZXN1bHQpKQ0Kc3BlY2lmaWNpdHkoYXMudGFibGUoY29fcmVzdWx0KSkNCnByZWNpc2lvbihhcy50YWJsZShjb19yZXN1bHQpKQ0KDQphY2MgPC0gY29fcmVzdWx0JG92ZXJhbGxbIkFjY3VyYWN5Il0NCmFjYw0KYGBgDQoNCg0KMi4gIEJ1aWxkaW5nIHRoZSBUcmVlIHVzaW5nIEdpbmkgSW5kZXgoQ0FSVCkNCg0KYGBge3J9DQojIEZvciBkZWNpc2lvbiB0cmVlIG1vZGVsDQppbnN0YWxsLnBhY2thZ2VzKCJycGFydCIpDQpsaWJyYXJ5KHJwYXJ0KQ0KIyBGb3IgZGF0YSB2aXN1YWxpemF0aW9uDQpsaWJyYXJ5KHJwYXJ0LnBsb3QpDQoNCmRhdGFzZXQuY2FydCA8LSBycGFydChteUZvcm11bGEsIGRhdGEgPSB0cmFpbkRhdGEsIG1ldGhvZCA9ICJjbGFzcyIsIHBhcm1zID0gbGlzdChzcGxpdCA9ICJnaW5pIikpDQpgYGANCg0KDQpWaXN1YWxpemluZyB0aGUgdW5wcnVuZWQgdHJlZQ0KDQpgYGB7cn0NCnJwYXJ0LnBsb3QoZGF0YXNldC5jYXJ0KQ0KYGBgDQoNCg0KQ2hlY2tpbmcgdGhlIG9yZGVyIG9mIHZhcmlhYmxlIGltcG9ydGFuY2UNCg0KYGBge3J9DQpkYXRhc2V0LmNhcnQkdmFyaWFibGUuaW1wb3J0YW5jZQ0KcHJlZC50cmVlID0gcHJlZGljdChkYXRhc2V0LmNhcnQsIHRlc3REYXRhLCB0eXBlID0gImNsYXNzIikNCg0KdGFibGUocHJlZC50cmVlLHRlc3REYXRhJGNsb3NlKQ0KYGBgDQoNCmBgYHtyfQ0KIyA1LlVzZSB0aGUgY29uc3RydWN0ZWQgbW9kZWwgdG8gcHJlZGljdCB0aGUgY2xhc3MgbGFiZWxzIG9mIHRlc3QgZGF0YToNCnRlc3RQcmVkIDwtIHByZWRpY3QoZGF0YXNldF9jdHJlZSwgbmV3ZGF0YSA9IHRlc3REYXRhKQ0KcmVzdWx0PC10YWJsZSh0ZXN0UHJlZCwgdGVzdERhdGEkY2xvc2UpDQpyZXN1bHQNCmBgYA0KDQpgYGB7cn0NCiMgRXZhbHVhdGUgdGhlIG1vZGVsIGFuZCBjcmVhdGUgY29uZnVzaW9uIG1hdHJpeA0KaW5zdGFsbC5wYWNrYWdlcygiY2FyZXQiKQ0KaW5zdGFsbC5wYWNrYWdlcygnZTEwNzEnLCBkZXBlbmRlbmNpZXM9VFJVRSkNCmxpYnJhcnkoZTEwNzEpDQpsaWJyYXJ5KGNhcmV0KQ0KDQpjb19yZXN1bHQgPC0gY29uZnVzaW9uTWF0cml4KHJlc3VsdCkNCg0KcHJpbnQoY29fcmVzdWx0KQ0Kc2Vuc2l0aXZpdHkoYXMudGFibGUoY29fcmVzdWx0KSkNCnNwZWNpZmljaXR5KGFzLnRhYmxlKGNvX3Jlc3VsdCkpDQpwcmVjaXNpb24oYXMudGFibGUoY29fcmVzdWx0KSkNCg0KYWNjIDwtIGNvX3Jlc3VsdCRvdmVyYWxsWyJBY2N1cmFjeSJdDQphY2MNCmBgYA0KDQoNCjMuICBCdWlsZGluZyB0aGUgVHJlZSB1c2luZyBHYWluIHJhdGlvKEM1KQ0KDQpgYGB7cn0NCmluc3RhbGwucGFja2FnZXMoImNhcmV0IikNCmluc3RhbGwucGFja2FnZXMoIkM1MCIpDQppbnN0YWxsLnBhY2thZ2VzKCJwcmludHIiKQ0KDQpsaWJyYXJ5KEM1MCkNCmxpYnJhcnkocHJpbnRyKQ0KbGlicmFyeShjYXJldCkNCiN0cmFpbiB1c2luZyB0aGUgdHJhaW5EYXRhIGFuZCBjcmVhdGUgdGhlIGM1LjAgZ2FpbiByYXRpbyB0cmVlDQpDbG9zZVRyZWUgPC0gQzUuMChteUZvcm11bGEsIGRhdGE9dHJhaW5EYXRhKQ0Kc3VtbWFyeShDbG9zZVRyZWUpDQpwbG90KENsb3NlVHJlZSkNCmBgYA0KDQoNClRoaXJkIG9uZSA4MC0yMCwgd2hpY2ggbWVhbnMgVHJhaW5pbmcoODAlKSBhbmQgVGVzdGluZygyMCUpOg0KDQpgYGB7cn0NCiMgYSBmaXhlZCByYW5kb20gc2VlZCB0byBtYWtlIHJlc3VsdHMgcmVwcm9kdWNpYmxlDQpzZXQuc2VlZCgxMjM0KQ0KDQojIDEuU3BsaXQgdGhlIGRhdGFzZXRzIGludG8gdHdvIHN1YnNldHM6IFRyYWluaW5nKDgwJSkgYW5kIFRlc3RpbmcoMjAlKToNCmluZDEgPC0gc2FtcGxlKDIsIG5yb3coZGF0YXNldCksIHJlcGxhY2U9VFJVRSwgcHJvYj1jKDAuODAgLCAwLjIwKSkNCnRyYWluRGF0YSAgPC0gZGF0YXNldFtpbmQxPT0xLF0NCnRlc3REYXRhIDwtIGRhdGFzZXRbaW5kMT09MixdDQpgYGANCg0KDQoyLkRldGVybWluZSB0aGUgcHJlZGljdG9yIGF0dHJpYnV0ZXMgYW5kIHRoZSBjbGFzcyBsYWJlbCBhdHRyaWJ1dGUuKCB0aGUgZm9ybXVsYSk6DQoNCmBgYHtyfQ0KbGlicmFyeShwYXJ0eSkgICAgDQojbXlGb3JtdWxhIA0KbXlGb3JtdWxhIDwtIGNsb3NlIH52b2x1bWUrb3BlbitoaWdoK2xvdw0KDQpgYGANCg0KDQozLkJ1aWxkIGEgZGVjaXNpb24gdHJlZSB1c2luZyB0cmFpbmluZyBzZXQgYW5kIGNoZWNrIHRoZSBQcmVkaWN0aW9uOg0KDQpgYGB7cn0NCmRhdGFzZXRfY3RyZWUgPC0gY3RyZWUobXlGb3JtdWxhLCBkYXRhPXRyYWluRGF0YSkNCnRhYmxlKHByZWRpY3QoZGF0YXNldF9jdHJlZSksIHRyYWluRGF0YSRjbG9zZSkNCiMgNC5QcmludCBhbmQgcGxvdCB0aGUgdHJlZToNCg0KcHJpbnQoZGF0YXNldF9jdHJlZSkNCnBsb3QoZGF0YXNldF9jdHJlZSwgdHlwZT0ic2ltcGxlIikNCmBgYA0KDQpgYGB7cn0NCiMgNS5Vc2UgdGhlIGNvbnN0cnVjdGVkIG1vZGVsIHRvIHByZWRpY3QgdGhlIGNsYXNzIGxhYmVscyBvZiB0ZXN0IGRhdGE6DQp0ZXN0UHJlZCA8LSBwcmVkaWN0KGRhdGFzZXRfY3RyZWUsIG5ld2RhdGEgPSB0ZXN0RGF0YSkNCnJlc3VsdDwtdGFibGUodGVzdFByZWQsIHRlc3REYXRhJGNsb3NlKQ0KcmVzdWx0DQpgYGANCg0KYGBge3J9DQojIEV2YWx1YXRlIHRoZSBtb2RlbCBhbmQgY3JlYXRlIGNvbmZ1c2lvbiBtYXRyaXgNCmluc3RhbGwucGFja2FnZXMoImNhcmV0IikNCmluc3RhbGwucGFja2FnZXMoJ2UxMDcxJywgZGVwZW5kZW5jaWVzPVRSVUUpDQpsaWJyYXJ5KGUxMDcxKQ0KbGlicmFyeShjYXJldCkNCg0KY29fcmVzdWx0IDwtIGNvbmZ1c2lvbk1hdHJpeChyZXN1bHQpDQoNCnByaW50KGNvX3Jlc3VsdCkNCnNlbnNpdGl2aXR5KGFzLnRhYmxlKGNvX3Jlc3VsdCkpDQpzcGVjaWZpY2l0eShhcy50YWJsZShjb19yZXN1bHQpKQ0KcHJlY2lzaW9uKGFzLnRhYmxlKGNvX3Jlc3VsdCkpDQoNCmFjYyA8LSBjb19yZXN1bHQkb3ZlcmFsbFsiQWNjdXJhY3kiXQ0KYWNjDQpgYGANCg0KDQoyLiAgQnVpbGRpbmcgdGhlIFRyZWUgdXNpbmcgR2luaSBJbmRleChDQVJUKQ0KDQpgYGB7cn0NCiMgRm9yIGRlY2lzaW9uIHRyZWUgbW9kZWwNCmluc3RhbGwucGFja2FnZXMoInJwYXJ0IikNCmxpYnJhcnkocnBhcnQpDQojIEZvciBkYXRhIHZpc3VhbGl6YXRpb24NCmxpYnJhcnkocnBhcnQucGxvdCkNCg0KZGF0YXNldC5jYXJ0IDwtIHJwYXJ0KG15Rm9ybXVsYSwgZGF0YSA9IHRyYWluRGF0YSwgbWV0aG9kID0gImNsYXNzIiwgcGFybXMgPSBsaXN0KHNwbGl0ID0gImdpbmkiKSkNCmBgYA0KDQoNClZpc3VhbGl6aW5nIHRoZSB1bnBydW5lZCB0cmVlDQoNCmBgYHtyfQ0KbGlicmFyeShycGFydC5wbG90KQ0KcnBhcnQucGxvdChkYXRhc2V0LmNhcnQpDQpgYGANCg0KDQpDaGVja2luZyB0aGUgb3JkZXIgb2YgdmFyaWFibGUgaW1wb3J0YW5jZQ0KDQpgYGB7cn0NCmRhdGFzZXQuY2FydCR2YXJpYWJsZS5pbXBvcnRhbmNlDQpwcmVkLnRyZWUgPSBwcmVkaWN0KGRhdGFzZXQuY2FydCwgdGVzdERhdGEsIHR5cGUgPSAiY2xhc3MiKQ0KDQp0YWJsZShwcmVkLnRyZWUsdGVzdERhdGEkY2xvc2UpDQpgYGANCg0KYGBge3J9DQojIDUuVXNlIHRoZSBjb25zdHJ1Y3RlZCBtb2RlbCB0byBwcmVkaWN0IHRoZSBjbGFzcyBsYWJlbHMgb2YgdGVzdCBkYXRhOg0KdGVzdFByZWQgPC0gcHJlZGljdChkYXRhc2V0X2N0cmVlLCBuZXdkYXRhID0gdGVzdERhdGEpDQpyZXN1bHQ8LXRhYmxlKHRlc3RQcmVkLCB0ZXN0RGF0YSRjbG9zZSkNCnJlc3VsdA0KYGBgDQoNCmBgYHtyfQ0KIyBFdmFsdWF0ZSB0aGUgbW9kZWwgYW5kIGNyZWF0ZSBjb25mdXNpb24gbWF0cml4DQppbnN0YWxsLnBhY2thZ2VzKCJjYXJldCIpDQppbnN0YWxsLnBhY2thZ2VzKCdlMTA3MScsIGRlcGVuZGVuY2llcz1UUlVFKQ0KbGlicmFyeShlMTA3MSkNCmxpYnJhcnkoY2FyZXQpDQoNCmNvX3Jlc3VsdCA8LSBjb25mdXNpb25NYXRyaXgocmVzdWx0KQ0KDQpwcmludChjb19yZXN1bHQpDQpzZW5zaXRpdml0eShhcy50YWJsZShjb19yZXN1bHQpKQ0Kc3BlY2lmaWNpdHkoYXMudGFibGUoY29fcmVzdWx0KSkNCnByZWNpc2lvbihhcy50YWJsZShjb19yZXN1bHQpKQ0KDQphY2MgPC0gY29fcmVzdWx0JG92ZXJhbGxbIkFjY3VyYWN5Il0NCmFjYw0KYGBgDQoNCg0KMy4gIEJ1aWxkaW5nIHRoZSBUcmVlIHVzaW5nIEdhaW4gcmF0aW8oQzUpDQoNCmBgYHtyfQ0KaW5zdGFsbC5wYWNrYWdlcygiY2FyZXQiKQ0KaW5zdGFsbC5wYWNrYWdlcygiQzUwIikNCmluc3RhbGwucGFja2FnZXMoInByaW50ciIpDQoNCmxpYnJhcnkoQzUwKQ0KbGlicmFyeShwcmludHIpDQpsaWJyYXJ5KGNhcmV0KQ0KI3RyYWluIHVzaW5nIHRoZSB0cmFpbkRhdGEgYW5kIGNyZWF0ZSB0aGUgYzUuMCBnYWluIHJhdGlvIHRyZWUNCkNsb3NlVHJlZSA8LSBDNS4wKG15Rm9ybXVsYSwgZGF0YT10cmFpbkRhdGEpDQpzdW1tYXJ5KENsb3NlVHJlZSkNCnBsb3QoQ2xvc2VUcmVlKQ0KYGBgDQoNCg0KYWZ0ZXIgZG9pbmcgYWxsIHRoZSB0aHJlZSBtZXRob2RzIHdlIGhhdmUgbm90aWNlZCB0aGF0IGluIElHIGFuZCBHaW5pDQpJbmRleChDQVJUKQ0KDQp0aGUgVHJhaW5pbmcoNzAlKSBhbmQgVGVzdGluZygzMCUpIGhhcyBzZW5zaXRpdml0eSA9IDAuOTk1OTAxNg0Kc3BlY2lmaWNpdHkgPSAwLjk2ODUwMzkgQWNjdXJhY3kgPSAwLjk4NjUyMjkNCg0KdGhlIFRyYWluaW5nKDYwJSkgYW5kIFRlc3RpbmcoNDAlKSBoYXMgc2Vuc2l0aXZpdHkgPSAwLjk5Njk1MTINCnNwZWNpZmljaXR5ID0gMC45NzEwOTgzIEFjY3VyYWN5ID0gMC45ODgwMjQNCg0KdGhlIFRyYWluaW5nKDgwJSkgYW5kIFRlc3RpbmcoMjAlKSBoYXMgc2Vuc2l0aXZpdHkgPSAwLjk5NDA0NzYNCnNwZWNpZmljaXR5ID0gMC45NjU1MTcyIEFjY3VyYWN5ID0gMC45ODQzMTM3DQoNCndoaWNoIG1lYW5zIHRoYXQgdGhlIGJlc3Qgc3BpbHRpbmcgaW4gb3VyIGRhdGFzZXQgaXMgdGhlICpUcmFpbmluZyg2MCUpDQphbmQgVGVzdGluZyg0MCUpKiBiZWNhdXNlIGl0IGlzIGhhcyB0aGUgaGlnaGVzdCBzZW5zaXRpdml0eSA9IDAuOTk0MDQ3Ng0KJTk5LjQgLCBzcGVjaWZpY2l0eSA9IDAuOTY1NTE3MiAlOTYuNSAsIEFjY3VyYWN5ID0gMC45ODgwMjQgJTk4LjgNCg0KDQoNCg0KLSAgICoqQ2x1c3RlcmluZyoqDQoNCkNsdXN0ZXJpbmcgaXMgdW5zdXBlcnZpc2VkIGxlYXJuaW5nLCBpdCBkb2VzbuKAmXQgdXNlIGEgY2xhc3MgbGFiZWwgZm9yIGltcGxlbWVudGluZyB0aGUgY2x1c3Rlci4gVG8gaW1wbGVtZW50IHRoZSBjbHVzdGVycywgd2UgdXNlZCB0aGUgSy1tZWFuIGFsZ29yaXRobSwgd2hpY2ggaXMgYW4gYWxnb3JpdGhtIHRoYXQgcHJvZHVjZXMgSyBjbHVzdGVycywgd2hpY2ggZWFjaCBjbHVzdGVyIGlzIHJlcHJlc2VudGVkIGJ5IHRoZSBjZW50ZXIgcG9pbnQgb2YgdGhlIGNsdXN0ZXIgYW5kIGFzc2lnbnMgZWFjaCBvYmplY3QgdG8gdGhlIG5lYXJlc3QgY2x1c3RlciwgdGhlbiBpdGVyYXRpdmVseSByZWNhbGN1bGF0ZXMgdGhlIGNlbnRlciwgYW5kIHJlYXNzaWducyB0aGUgb2JqZWN0IHVudGlsIHRoZSBjZW50ZXIgcG9pbnQgb2YgZWFjaCBjbHVzdGVyIGRvZXMgbm90IGNoYW5nZSB0aGF0IG1lYW5zIHRoZSBvYmplY3QgaW4gdGhlIHJpZ2h0IGNsdXN0ZXIuDQoNCmZhY3RvZXh0cmEgcGFja2FnZXMgaXMgdXNlZCB0byBoZWxwIGluIGltcGxlbWVudGluZyB0aGUgY2x1c3RlcmluZyB0ZWNobmlxdWUuIHNjYWxlKCkgbWV0aG9kIGlzIHVzZWQgZm9yIHNjYWxpbmcgYW5kIGNlbnRlcmluZyBvZiBkYXRhIHNldCBvYmplY3RzLCBLbWVhbnMoKSBtZXRob2QgdG8gZmluZCBhIHNwZWNpZmllZCBudW1iZXIgb2YgY2x1c3RlcnMuIGZ2aXpfY2x1c3RlcigpIG1ldGhvZCB0byB2aXN1YWxpemUgdGhlIGNsdXN0ZXJzIGRpYWdyYW0uIHNpbGhvdWV0dGUoKSBtZXRob2QgdG8gY2FsY3VsYXRlIHRoZSBhdmVyYWdlIGZvciBlYWNoIGNsdXN0ZXIsIGZ2aXpfc2lsaG91ZXR0ZSgpIHRvIHZpc3VhbGl6ZSBpdCwgYW5kIGZ2aXpfbmJjbHVzdCgpIG1ldGhvZCB0byBzZXQgYSBjb21wYXJpc29uIGJldHdlZW4gdGhlIHRocmVlIGRpZmZlcmVudCBudW1iZXJzIG9mIGNsdXN0ZXJzIHRvIGZpbmQgdGhlIG9wdGltYWwgbnVtYmVyIGJ5IGV2YWx1YXRpbmcgdGhlIGNsdXN0ZXJzIGFjY29yZGluZyB0byBob3cgd2VsbCB0aGUgY2x1c3RlcnMgYXJlIHNlcGFyYXRlZCwgYW5kIGhvdyBjb21wYWN0IHRoZSBjbHVzdGVycyBhcmUuIEluIGJvdGggdGVjaG5pcXVlcywgd2UgdXNlZCB0aGUgbWV0aG9kIHNldC5zZWVkKCkgd2l0aCB0aGUgc2FtZSByYW5kb20gbnVtYmVyIGVhY2ggdGltZSB3ZSB0cnkgYSBkaWZmZXJlbnQgc2l6ZSB0byBlbnN1cmUgdGhhdCB3ZSBnZXQgdGhlIHNhbWUgcmVzdWx0IGVhY2ggdGltZS4NCg0KDQpEYXRhIHR5cGVzIHNob3VsZCBiZSB0cmFuc2Zvcm1lZCBpbnRvIG51bWVyaWMgdHlwZXMgYmVmb3JlIGNsdXN0ZXJpbmcuDQoNCmBgYHtyfQ0KIyBwcmVwcmVvY2Vzc2luZyANCiNEYXRhIHR5cGVzIHNob3VsZCBiZSB0cmFuc2Zvcm1lZCBpbnRvIG51bWVyaWMgdHlwZXMgYmVmb3JlIGNsdXN0ZXJpbmcuDQpkYXRhc2V0IDwtIHNjYWxlKGRhdGFzZXQpDQpWaWV3KGRhdGFzZXQpDQpgYGANCg0KDQotIEFwcGx5IGstbWVhbnMgY2x1c3RlcmluZyBmb3IgdmFsdWUgNA0KDQpgYGB7cn0NCiMgay1tZWFucyBjbHVzdGVyaW5nIHRvIGZpbmQgNCBjbHVzdGVycyANCiNzZXQgYSBzZWVkIGZvciByYW5kb20gbnVtYmVyIGdlbmVyYXRpb24gIHRvIG1ha2UgdGhlIHJlc3VsdHMgcmVwcm9kdWNpYmxlDQpzZXQuc2VlZCg4OTUzKQ0Ka21lYW5zLnJlc3VsdCA8LSBrbWVhbnMoZGF0YXNldCwgNCkNCmBgYA0KDQp2aXN1YWxpemF0aW9uIG9mIDQgY2x1c3RlcnMNCg0KYGBge3J9DQojIHZpc3VhbGl6ZSBjbHVzdGVyaW5nDQojaW5zdGFsbC5wYWNrYWdlcygiZmFjdG9leHRyYSIpDQpsaWJyYXJ5KGZhY3RvZXh0cmEpDQpmdml6X2NsdXN0ZXIoa21lYW5zLnJlc3VsdCwgZGF0YSA9IGRhdGFzZXQpDQpgYGANCg0KYXZlcmFnZSBzaWxob3VldHRlIHdpZHRoIGZvciBlYWNoIGNsdXN0ZXJzIA0KDQpgYGB7cn0NCiNhdmVyYWdlIHNpbGhvdWV0dGUgZm9yIGVhY2ggY2x1c3RlcnMgDQpsaWJyYXJ5KGNsdXN0ZXIpDQphdmdfc2lsIDwtIHNpbGhvdWV0dGUoa21lYW5zLnJlc3VsdCRjbHVzdGVyLGRpc3QoZGF0YXNldCkpIA0KI2EgZGlzc2ltaWxhcml0eSBvYmplY3QgaW5oZXJpdGluZyBmcm9tIGNsYXNzIGRpc3Qgb3IgY29lcmNpYmxlIHRvIG9uZS4gSWYgbm90IHNwZWNpZmllZCwgZG1hdHJpeCBtdXN0IGJlLg0KZnZpel9zaWxob3VldHRlKGF2Z19zaWwpI2stbWVhbnMgY2x1c3RlcmluZyB3aXRoIGVzdGltYXRpbmcgayBhbmQgaW5pdGlhbGl6YXRpb25zDQpgYGANCg0KdG90YWwgd2l0aGluLWNsdXN0ZXIgc3VtIG9mIHNxdWFyZSBhbmQgQkN1YmVkIHByZWNpc2lvbiBhbmQgcmVjYWxsDQoNCmBgYHtyfQ0KIyBUb3RhbCBzdW0gb2Ygc3F1YXJlcw0Ka21lYW5zLnJlc3VsdCR0b3Qud2l0aGluc3MNCg0KI2JjdWJlZCBtZXRyaXggdGhhdCB0YWtlIHRoZSBhdmcgb2YgcHJlY2lzaW9uJnJlY2FsbA0KbGlicmFyeSgnRFBCQk0nKQ0KYyA9IGttZWFucy5yZXN1bHQkY2x1c3Rlcg0KQkN1YmVkX21ldHJpYyhrbWVhbnMucmVzdWx0JGNsdXN0ZXIsIDAuNTApDQpgYGANCg0KcHJpbnQgdGhlIGNsdXN0ZXJpbmcgcmVzdWx0DQpgYGB7cn0NCiMgcHJpbnQgdGhlIGNsdXN0ZXJpbmcgcmVzdWx0DQpwcmludChrbWVhbnMucmVzdWx0KQ0KYGBgDQoNCg0KQXBwbHkgay1tZWFucyBjbHVzdGVyaW5nIGZvciB2YWx1ZSAzDQoNCmBgYHtyfQ0KIyBydW4gay1tZWFucyBjbHVzdGVyaW5nIHRvIGZpbmQgMyBjbHVzdGVycw0KI3NldCBhIHNlZWQgZm9yIHJhbmRvbSBudW1iZXIgZ2VuZXJhdGlvbiAgdG8gbWFrZSB0aGUgcmVzdWx0cyByZXByb2R1Y2libGUNCnNldC5zZWVkKDg5NTMpDQprbWVhbnMucmVzdWx0IDwtIGttZWFucyhkYXRhc2V0LCAzKQ0KYGBgDQoNCnZpc3VhbGl6YXRpb24gb2YgMyBjbHVzdGVycw0KDQpgYGB7cn0NCiMgdmlzdWFsaXplIGNsdXN0ZXJpbmcNCiNpbnN0YWxsLnBhY2thZ2VzKCJmYWN0b2V4dHJhIikNCmxpYnJhcnkoZmFjdG9leHRyYSkNCmZ2aXpfY2x1c3RlcihrbWVhbnMucmVzdWx0LCBkYXRhID0gZGF0YXNldCkNCmBgYA0KDQphdmVyYWdlIHNpbGhvdWV0dGUgd2lkdGggZm9yIGVhY2ggY2x1c3RlcnMgDQpgYGB7cn0NCiNhdmVyYWdlIHNpbGhvdWV0dGUgZm9yIGVhY2ggY2x1c3RlcnMgDQpsaWJyYXJ5KGNsdXN0ZXIpDQphdmdfc2lsIDwtIHNpbGhvdWV0dGUoa21lYW5zLnJlc3VsdCRjbHVzdGVyLGRpc3QoZGF0YXNldCkpIA0KI2EgZGlzc2ltaWxhcml0eSBvYmplY3QgaW5oZXJpdGluZyBmcm9tIGNsYXNzIGRpc3Qgb3IgY29lcmNpYmxlIHRvIG9uZS4gSWYgbm90IHNwZWNpZmllZCwgZG1hdHJpeCBtdXN0IGJlLg0KZnZpel9zaWxob3VldHRlKGF2Z19zaWwpI2stbWVhbnMgY2x1c3RlcmluZyB3aXRoIGVzdGltYXRpbmcgayBhbmQgaW5pdGlhbGl6YXRpb25zDQpgYGANCg0KdG90YWwgd2l0aGluLWNsdXN0ZXIgc3VtIG9mIHNxdWFyZSBhbmQgQkN1YmVkIHByZWNpc2lvbiBhbmQgcmVjYWxsDQoNCmBgYHtyfQ0KIyBUb3RhbCBzdW0gb2Ygc3F1YXJlcw0Ka21lYW5zLnJlc3VsdCR0b3Qud2l0aGluc3MNCg0KI2JjdWJlZCBtZXRyaXggdGhhdCB0YWtlIHRoZSBhdmcgb2YgcHJlY2lzaW9uJnJlY2FsbA0KbGlicmFyeSgnRFBCQk0nKQ0KYyA9IGttZWFucy5yZXN1bHQkY2x1c3Rlcg0KQkN1YmVkX21ldHJpYyhrbWVhbnMucmVzdWx0JGNsdXN0ZXIsIDAuNikNCmBgYA0KDQpwcmludCB0aGUgY2x1c3RlcmluZyByZXN1bHQNCmBgYHtyfQ0KIyBwcmludCB0aGUgY2x1c3RlcmluZyByZXN1bHQNCnByaW50KGttZWFucy5yZXN1bHQpDQpgYGANCg0KDQpBcHBseSBrLW1lYW5zIGNsdXN0ZXJpbmcgZm9yIHZhbHVlIDINCg0KYGBge3J9DQojIHJ1biBrLW1lYW5zIGNsdXN0ZXJpbmcgdG8gZmluZCAyIGNsdXN0ZXJzDQojc2V0IGEgc2VlZCBmb3IgcmFuZG9tIG51bWJlciBnZW5lcmF0aW9uICB0byBtYWtlIHRoZSByZXN1bHRzIHJlcHJvZHVjaWJsZQ0Kc2V0LnNlZWQoODk1MykNCmttZWFucy5yZXN1bHQgPC0ga21lYW5zKGRhdGFzZXQsIDIpDQpgYGANCg0KDQp2aXN1YWxpemF0aW9uIG9mIDMgY2x1c3RlcnMNCg0KYGBge3J9DQojIHZpc3VhbGl6ZSBjbHVzdGVyaW5nDQojaW5zdGFsbC5wYWNrYWdlcygiZmFjdG9leHRyYSIpDQpsaWJyYXJ5KGZhY3RvZXh0cmEpDQpmdml6X2NsdXN0ZXIoa21lYW5zLnJlc3VsdCwgZGF0YSA9IGRhdGFzZXQpDQpgYGANCg0KYXZlcmFnZSBzaWxob3VldHRlIHdpZHRoIGZvciBlYWNoIGNsdXN0ZXJzIA0KYGBge3J9DQojYXZlcmFnZSBzaWxob3VldHRlIGZvciBlYWNoIGNsdXN0ZXJzIA0KbGlicmFyeShjbHVzdGVyKQ0KYXZnX3NpbCA8LSBzaWxob3VldHRlKGttZWFucy5yZXN1bHQkY2x1c3RlcixkaXN0KGRhdGFzZXQpKSANCiNhIGRpc3NpbWlsYXJpdHkgb2JqZWN0IGluaGVyaXRpbmcgZnJvbSBjbGFzcyBkaXN0IG9yIGNvZXJjaWJsZSB0byBvbmUuIElmIG5vdCBzcGVjaWZpZWQsIGRtYXRyaXggbXVzdCBiZS4NCmZ2aXpfc2lsaG91ZXR0ZShhdmdfc2lsKSNrLW1lYW5zIGNsdXN0ZXJpbmcgd2l0aCBlc3RpbWF0aW5nIGsgYW5kIGluaXRpYWxpemF0aW9ucw0KYGBgDQoNCnRvdGFsIHdpdGhpbi1jbHVzdGVyIHN1bSBvZiBzcXVhcmUgYW5kIEJDdWJlZCBwcmVjaXNpb24gYW5kIHJlY2FsbA0KDQpgYGB7cn0NCiMgVG90YWwgc3VtIG9mIHNxdWFyZXMNCmttZWFucy5yZXN1bHQkdG90LndpdGhpbnNzDQoNCiNiY3ViZWQgbWV0cml4IHRoYXQgdGFrZSB0aGUgYXZnIG9mIHByZWNpc2lvbiZyZWNhbGwNCmxpYnJhcnkoJ0RQQkJNJykNCmMgPSBrbWVhbnMucmVzdWx0JGNsdXN0ZXINCkJDdWJlZF9tZXRyaWMoa21lYW5zLnJlc3VsdCRjbHVzdGVyLCAwLjYpDQpgYGANCg0KcHJpbnQgdGhlIGNsdXN0ZXJpbmcgcmVzdWx0DQpgYGB7cn0NCiMgcHJpbnQgdGhlIGNsdXN0ZXJpbmcgcmVzdWx0DQpwcmludChrbWVhbnMucmVzdWx0KQ0KYGBgDQoNCg0KDQprbWVhbnNydW5zKCkgY2FsbHMgIGttZWFucygpIHRvIHBlcmZvcm0gIGstbWVhbnMgY2x1c3RlcmluZw0KSXQgaW5pdGlhbGl6ZXMgdGhlIGstbWVhbnMgYWxnb3JpdGhtIHNldmVyYWwgdGltZXMgd2l0aCByYW5kb20gcG9pbnRzIGZyb20gdGhlIGRhdGEgc2V0IGFzIG1lYW5zLg0KSXQgZXN0aW1hdGVzIHRoZSBudW1iZXIgb2YgY2x1c3RlcnMgYnkgaW5kZXggb3IgYXZlcmFnZSBzaWxob3VldHRlIHdpZHRoDQoNCmBgYHtyfQ0KaW5zdGFsbC5wYWNrYWdlcygiZnBjIikNCmxpYnJhcnkoZnBjKQ0KI2ttZWFuc3J1bnMoKSA6IEl0IGNhbGxzICBrbWVhbnMoKSB0byBwZXJmb3JtICBrLW1lYW5zIGNsdXN0ZXJpbmcNCiNJdCBpbml0aWFsaXplcyB0aGUgay1tZWFucyBhbGdvcml0aG0gc2V2ZXJhbCB0aW1lcyB3aXRoIHJhbmRvbSBwb2ludHMgZnJvbSB0aGUgZGF0YSBzZXQgYXMgbWVhbnMuDQojSXQgZXN0aW1hdGVzIHRoZSBudW1iZXIgb2YgY2x1c3RlcnMgYnkgaW5kZXggb3IgYXZlcmFnZSBzaWxob3VldHRlIHdpZHRoDQprbWVhbnNydW5zLnJlc3VsdCA8LSBrbWVhbnNydW5zKGRhdGFzZXQpICANCmttZWFuc3J1bnMucmVzdWx0DQpmdml6X2NsdXN0ZXIoa21lYW5zcnVucy5yZXN1bHQsIGRhdGEgPSBkYXRhc2V0KQ0KYGBgDQoNCg0Kay1tZWRpb2RzIGNsdXN0ZXJpbmcgd2l0aCBQQU0NCg0KYGBge3J9DQojaW5zdGFsbC5wYWNrYWdlcygiY2x1c3RlciIpDQpsaWJyYXJ5KGNsdXN0ZXIpDQojIGdyb3VwIGludG8gNCBjbHVzdGVycw0KcGFtLnJlc3VsdCA8LSBwYW0oZGF0YXNldCwgNCkNCnBsb3QocGFtLnJlc3VsdCkNCmBgYA0KDQoNCkhpZXJhcmNoaWNhbCBDbHVzdGVyaW5nDQpkcmF3IGEgc2FtcGxlIG9mIDQwIHJlY29yZHMgZnJvbSB0aGUgZGF0YXNldCBkYXRhLCBzbyB0aGF0IHRoZSBjbHVzdGVyaW5nIHBsb3Qgd2lsbCBub3QgYmUgb3ZlciBjcm93ZGVkDQoNCmBgYHtyfQ0KIyMtLS0tSGllcmFyY2hpY2FsIENsdXN0ZXJpbmcgb2YgdGhlIERhdGEtLS0tLSMjDQpzZXQuc2VlZCgyODM1KQ0KIyBkcmF3IGEgc2FtcGxlIG9mIDQwIHJlY29yZHMgZnJvbSB0aGUgZGF0YXNldCBkYXRhLCBzbyB0aGF0IHRoZSBjbHVzdGVyaW5nIHBsb3Qgd2lsbCBub3QgYmUgb3ZlciBjcm93ZGVkDQppZHggPC0gc2FtcGxlKDE6ZGltKGRhdGFzZXQpWzFdLCA0MCkNCmRhdGFzZXQyIDwtIGRhdGFzZXRbaWR4LCBdDQojIyBoaWVyY3JjaGljYWwgY2x1c3RlcmluZw0KbGlicmFyeShmYWN0b2V4dHJhKSANCmhjLmN1dCA8LSBoY3V0KGRhdGFzZXQyLCBrID0gMiwgaGNfbWV0aG9kID0gImNvbXBsZXRlIikgIyBDb21wdXRlcyBIaWVyYXJjaGljYWwgQ2x1c3RlcmluZyBhbmQgQ3V0IHRoZSBUcmVlDQoNCmBgYA0KDQoNCmBgYHtyfQ0KIyBWaXN1YWxpemUgZGVuZHJvZ3JhbQ0KZnZpel9kZW5kKGhjLmN1dCxyZWN0ID0gVFJVRSkgICNsb2dpY2FsIHZhbHVlIHNwZWNpZnlpbmcgd2hldGhlciB0byBhZGQgYSByZWN0YW5nbGUgYXJvdW5kIGdyb3Vwcy4NCiMgVmlzdWFsaXplIGNsdXN0ZXINCmZ2aXpfY2x1c3RlcihoYy5jdXQsIGVsbGlwc2UudHlwZSA9ICJjb252ZXgiKSAjIENoYXJhY3RlciBzcGVjaWZ5aW5nIGZyYW1lIHR5cGUuIFBvc3NpYmxlIHZhbHVlcyBhcmUgJ2NvbnZleCcsICdjb25maWRlbmNlJyBldGMNCg0KYGBgDQoNCg0KDQpkZWZpbmUgZnVuY3Rpb24gdG8gY29tcHV0ZSBhdmVyYWdlIHNpbGhvdWV0dGUgZm9yIGsgY2x1c3RlcnMgdXNpbmcNCnNpbGhvdWV0dGUoKQ0KDQpgYGB7cn0NCnNpbGhvdWV0dGVfc2NvcmUgPC0gZnVuY3Rpb24oayl7IA0KICBrbSA8LSBrbWVhbnMoVVNBcnJlc3RzLCBjZW50ZXJzID0gayxuc3RhcnQ9MjUpICMgaWYgY2VudGVycyBpcyBhIG51bWJlciwgaG93IG1hbnkgcmFuZG9tIHNldHMgc2hvdWxkIGJlIGNob3Nlbj8NCiAgc3MgPC0gc2lsaG91ZXR0ZShrbSRjbHVzdGVyLCBkaXN0KFVTQXJyZXN0cykpDQogIHNpbDwtIG1lYW4oc3NbLCAzXSkNCiAgcmV0dXJuKHNpbCkNCn0NCmBgYA0KDQotICBPcHRpbWFsIG51bWJlciBvZiBjbHVzdGVyczoNCg0KYGBge3J9DQojIGsgY2x1c3RlciByYW5nZSBmcm9tIDIgdG8gMTANCmsgPC0gMjoxMA0KIyMgIGNhbGwgIGZ1bmN0aW9uIGZvcmUgayB2YWx1ZQ0KYXZnX3NpbCA8LSBzYXBwbHkoaywgc2lsaG91ZXR0ZV9zY29yZSkgICMjQXBwbHkgYSBGdW5jdGlvbiBvdmVyIGEgTGlzdCBvciBWZWN0b3INCnBsb3QoaywgdHlwZT0nYicsIGF2Z19zaWwsIHhsYWI9J051bWJlciBvZiBjbHVzdGVycycsIHlsYWI9J0F2ZXJhZ2UgU2lsaG91ZXR0ZSBTY29yZXMnLCBmcmFtZT1GQUxTRSkNCg0KYGBgDQoNCg0Kc2lsaG91ZXR0ZSBtZXRob2QNCg0KYGBge3J9DQojaW5zdGFsbC5wYWNrYWdlcygiTmJDbHVzdCIpDQpsaWJyYXJ5KE5iQ2x1c3QpDQojYSlmdml6X25iY2x1c3QoKSB3aXRoIHNpbGhvdWV0dGUgbWV0aG9kIHVzaW5nIGxpYnJhcnkoZmFjdG9leHRyYSkgDQpmdml6X25iY2x1c3QoZGF0YXNldCwga21lYW5zLCBtZXRob2QgPSAic2lsaG91ZXR0ZSIpKw0KICBsYWJzKHN1YnRpdGxlID0gIlNpbGhvdWV0dGUgbWV0aG9kIikNCmBgYA0KDQpgYGB7cn0NCiNiKSBOYkNsdXN0IHZhbGlkYXRpb24NCmZyZXMubmJjbHVzdCA8LSBOYkNsdXN0KGRhdGFzZXQsIGRpc3RhbmNlPSJldWNsaWRlYW4iLCBtaW4ubmMgPSAyLCBtYXgubmMgPSAxMCwgbWV0aG9kPSJrbWVhbnMiLCBpbmRleD0iYWxsIikNCmBgYA0KDQpgYGB7cn0NCiMgRWxib3cgbWV0aG9kIGZvciBkZXRlcm1pbmluZyB0aGUgb3B0aW1hbCBudW1iZXIgb2YgY2x1c3RlcnMgKGstbWVhbnMpDQp3c3MgPC0gbnVtZXJpYyhsZW5ndGggPSAxMCkNCmZvciAoayBpbiAxOjEwKSB7DQogIGttZWFuc19tb2RlbCA8LSBrbWVhbnMoZGF0YXNldCwgY2VudGVycyA9IGssIG5zdGFydCA9IDEwKQ0KICB3c3Nba10gPC0gc3VtKGttZWFuc19tb2RlbCRjbG9zZSkNCn0NCmBgYA0KDQoNCmFmdGVyIGRvaW5nIDMgc2l6ZXMgb2YgayBhbmQgYmFzZWQgdGhlIHBsb3QgYW5kIGRyYXdpbmcgd2UgaGF2ZSBub3RpY2VkDQp0aGF0IFRoZSBiZXN0IHNpemUgaXMgSyAyICwgaXQgaXMgUGFydGl0aW9uIGJldHRlciB0aGFuIHRoZSBvdGhlcg0KDQpgYGB7cn0NCiMgRXh0cmFjdCB0aGUgdG90YWwgd2l0aGluLWNsdXN0ZXIgc3VtIG9mIHNxdWFyZXMgKFRXU1MpDQp0d3NzIDwtIHN1bShrbWVhbnMucmVzdWx0JHdpdGhpbnNzKQ0KIyBQcmludCB0aGUgVFdTUw0KY2F0KHBhc3RlKCJUb3RhbCBXaXRoaW4tQ2x1c3RlciBTdW0gb2YgU3F1YXJlcyAoVFdTUyk6IiwgdHdzcywgIlxuIikpDQpgYGANCg0KYGBge3J9DQojIEV2YWx1YXRlIEJDdWJlZCBwcmVjaXNpb24gYW5kIHJlY2FsbCBmb3Igay1tZWRvaWRzDQojIEluc3RhbGwgYW5kIGxvYWQgcmVxdWlyZWQgbGlicmFyaWVzDQpsaWJyYXJ5KGNhcmV0KQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShsYXR0aWNlKQ0KDQoNCiMgQXNzdW1pbmcgeW91IGhhdmUgdHJ1ZSBsYWJlbHMgYW5kIHByZWRpY3RlZCBsYWJlbHMNCnRydWVfbGFiZWxzIDwtIGMoMSwgMSwgMSwgMCwgMCwgMSwgMCwgMSwgMCwgMSkNCnByZWRpY3RlZF9sYWJlbHMgPC0gYygxLCAwLCAxLCAwLCAwLCAxLCAwLCAxLCAxLCAxKQ0KDQojIENyZWF0ZSBhIGNvbmZ1c2lvbiBtYXRyaXgNCmNvbmZfbWF0cml4IDwtIGNvbmZ1c2lvbk1hdHJpeChmYWN0b3IocHJlZGljdGVkX2xhYmVscyksIGZhY3Rvcih0cnVlX2xhYmVscykpDQoNCiMgRXh0cmFjdCByZWNhbGwgZnJvbSB0aGUgY29uZnVzaW9uIG1hdHJpeA0KcmVjYWxsIDwtIGNvbmZfbWF0cml4JGJ5Q2xhc3NbIlNlbnNpdGl2aXR5Il0NCg0KIyBQcmludCB0aGUgcmVzdWx0DQpjYXQocGFzdGUoIlJlY2FsbDoiLCByZWNhbGwsICJcbiIpKQ0KYGBgDQoNCg0KIyAgNy4gIEZpbmRpbmdzDQoNCk91ciBkYXRhc2V0IHJlcHJlc2VudHMgb3BlbmluZyBhbmQgY2xvc2luZyBwcmljZXMgb2YgZ29vZ2xlIHN0b2NrcyBpbiBtYXJrZXQuIE91ciBnb2FsIHdhcyB0byBwcmVkaWN0IGhpZ2hlciBjbG9zaW5nIHByaWNlcyB0aGF0IGluZGljYXRlIGEgcG9zaXRpdmUgdHJlbmQgaW4gR29vZ2xlIHN0b2NrLiANClRvIGhhdmUgdGhlIGJlc3QsIGFjY3VyYXRlLCBhbmQgcHJlY2lzZSByZXN1bHRzIHdlIHVzZWQgc2V2ZXJhbCBkYXRhIG1pbmluZyBwcmVwcm9jZXNzaW5nIHRlY2huaXF1ZXMgdGhhdCBpbXByb3ZlIHRoZSBlZmZpY2llbmN5IG9mIHRoZSBkYXRhLiBhcHBsaWVkIHNldmVyYWwgcGxvdHRpbmcgbWV0aG9kcyB3YXMgYXBwbGllZCB0byBoZWxwIHVzIHVuZGVyc3RhbmQgb3VyIGRhdGEuIEJhc2VkIG9uIHBsb3RzIHdlIHJlbW92ZWQgb3V0bGllcnMsIHdlIGRpZG7igJl0IGZpbmQgYW55IG51bGwgb3IgbWlzc2luZyB2YWx1ZXMuIEFuZCB0aGVuIGRhdGEgdHJhbnNmb3JtYXRpb24gd2FzIGFwcGxpZWQgdG8gdHJhbnNmb3JtIGF0dHJpYnV0ZSB2YWx1ZXMgc3VjaCBhcyBub3JtYWxpemF0aW9uIGRpc2NyZXRpemF0aW9uLg0KDQpUaGVuIHdlIGFwcGxpZWQgdGhlIGRhdGEgbWluaW5nIHRhc2tzLCB0aGF0IGFyZSBjbGFzc2lmaWNhdGlvbiBhbmQgY2x1c3RlcmluZy4gDQpGb3IgY2xhc3NpZmljYXRpb24sIHdlIHVzZSB0aGUgZGVjaXNpb24gdHJlZSBtZXRob2QgdG8gY29uc3RydWN0IG91ciBtb2RlbCwgMyBkaWZmZXJlbnQgc2l6ZXMgb2YgdHJhaW5pbmcgYW5kIHRlc3RpbmcgZGF0YSB3ZXJlIHVzZWQgdG8gZ2V0IHRoZSBiZXN0IHJlc3VsdCBmb3IgY29uc3RydWN0aW9uIGFuZCBldmFsdWF0aW9uLg0KdGhlIGZvbGxvd2luZyByZXN1bHRzIGZvciBkaWZmZXJlbnQgc2l6ZXM6DQoNCi0gNzAlIFRyYWluaW5nIGFuZCAzMCUgVGVzdGluZyBkYXRhDQotIEluZm9ybWF0aW9uIEdhaW46DQogIEFjY3VyYWN5ID0gMC45ODY1MjI5DQogIHByZWNpc2lvbiA9IA0KICBzZW5zaXRpdml0eSA9IDAuOTk1OTAxNiANCiAgc3BlY2lmaWNpdHkgPSAwLjk2ODUwMzkgDQogIA0KLSBJbmZvcm1hdGlvbiBHYWluIHJhdGlvOg0KICBBY2N1cmFjeSA9IA0KICBwcmVjaXNpb24gPSANCiAgc2Vuc2l0aXZpdHkgPSANCiAgc3BlY2lmaWNpdHkgPSANCiAgDQotIEluZm9ybWF0aW9uIEdhaW4gaW5kZXg6DQogIEFjY3VyYWN5ID0gDQogIHByZWNpc2lvbiA9IA0KICBzZW5zaXRpdml0eSA9IA0KICBzcGVjaWZpY2l0eSA9IA0KICANCi0gNjAlIFRyYWluaW5nIGFuZCA0MCUgVGVzdGluZyBkYXRhDQotIEluZm9ybWF0aW9uIEdhaW46DQogIEFjY3VyYWN5ID0gMC45ODgwMjQNCiAgcHJlY2lzaW9uID0gDQogIHNlbnNpdGl2aXR5ID0gMC45OTY5NTEyIA0KICBzcGVjaWZpY2l0eSA9IDAuOTcxMDk4MyANCiAgDQotIEluZm9ybWF0aW9uIEdhaW4gcmF0aW86DQogIEFjY3VyYWN5ID0gDQogIHByZWNpc2lvbiA9IA0KICBzZW5zaXRpdml0eSA9IA0KICBzcGVjaWZpY2l0eSA9IA0KICANCi0gSW5mb3JtYXRpb24gR2FpbiBpbmRleDoNCiAgQWNjdXJhY3kgPSANCiAgcHJlY2lzaW9uID0gDQogIHNlbnNpdGl2aXR5ID0gDQogIHNwZWNpZmljaXR5ID0gDQogIA0KLSA4MCUgVHJhaW5pbmcgYW5kIDIwJSBUZXN0aW5nIGRhdGENCi0gSW5mb3JtYXRpb24gR2FpbjoNCiAgQWNjdXJhY3kgPSAwLjk4NDMxMzcNCiAgcHJlY2lzaW9uID0gDQogIHNlbnNpdGl2aXR5ID0gMC45OTQwNDc2IA0KICBzcGVjaWZpY2l0eSA9IDAuOTY1NTE3MiANCiAgDQotIEluZm9ybWF0aW9uIEdhaW4gcmF0aW86DQogIEFjY3VyYWN5ID0gDQogIHByZWNpc2lvbiA9IA0KICBzZW5zaXRpdml0eSA9IA0KICBzcGVjaWZpY2l0eSA9IA0KICANCi0gSW5mb3JtYXRpb24gR2FpbiBpbmRleDoNCiAgQWNjdXJhY3kgPSANCiAgcHJlY2lzaW9uID0gDQogIHNlbnNpdGl2aXR5ID0gDQogIHNwZWNpZmljaXR5ID0gDQoNCg0KSW4gY29uY2x1c2lvbiwgdGhlIG1vc3QgYWNjdXJhdGUgbW9kZWwgYW5kIHRoZSBiZXN0IHNwaWx0aW5nIGluIG91ciBkYXRhc2V0IGlzIHRoZSBUcmFpbmluZyg2MCUpIGFuZCBUZXN0aW5nKDQwJSkgYmVjYXVzZSBpdCBpcyBoYXMgdGhlIGhpZ2hlc3Qgc2Vuc2l0aXZpdHkgPSAwLjk5NDA0NzYgJTk5LjQgLCBzcGVjaWZpY2l0eSA9IDAuOTY1NTE3MiAlOTYuNSAsIEFjY3VyYWN5ID0gMC45ODgwMjQgJTk4LjguDQoNCkZvciBDbHVzdGVyaW5nLCAzIGRpZmZlcmVudCBzaXplcyBLIHdlcmUgdXNlZCBpbiBLLW1lYW5zIGFsZ29yaXRobSB0byBmaW5kIHRoZSBvcHRpbWFsIG51bWJlciBvZiBjbHVzdGVycy4gYXZlcmFnZSBzaWxob3VldHRlIHdpZHRoIGZvciBlYWNoIEsgd2FzIGNhbGN1bGF0ZWQgdG8gY29uY2x1ZGUgc2hvd24gcmVzdWx0cy4NCg0KLSBOdW1iZXIgb2YgY2x1c3RlcihLKT0gNCANCiAgYXZlcmFnZSBzaWxob3VldHRlIHdpZHRoPTAuNDMNCiAgc3VtIG9mIHNxdWFyZXM9IDE5MDAuMTI3DQogIEJDdWJlZCBwcmVjaXNpb249IA0KICBCQ3ViZWQgcmVjYWxsPSANCiAgDQotIE51bWJlciBvZiBjbHVzdGVyKEspPSAzDQogIGF2ZXJhZ2Ugc2lsaG91ZXR0ZSB3aWR0aD0wLjM3DQogIHN1bSBvZiBzcXVhcmVzPSAyOTA4Ljk1NQ0KICBCQ3ViZWQgcHJlY2lzaW9uPSANCiAgQkN1YmVkIHJlY2FsbD0gDQogIA0KLSBOdW1iZXIgb2YgY2x1c3RlcihLKT0gMg0KICBhdmVyYWdlIHNpbGhvdWV0dGUgd2lkdGg9MC40NQ0KICBzdW0gb2Ygc3F1YXJlcz0gNDEyNg0KICBCQ3ViZWQgcHJlY2lzaW9uPSANCiAgQkN1YmVkIHJlY2FsbD0gDQoNClNpbmNlIHRoZSBoaWdoZXN0IGF2ZXJhZ2Ugc2lsaG91ZXR0ZSB3aWR0aCBpcyB3aGVyZSB0aGUgbnVtYmVyIG9mIGNsdXN0ZXJzIGVxdWFscyB0byAyIGl0IGhhcyB0aGUgb3B0aW1hbCBudW1iZXIgb2YgY2x1c3RlcnMuIFRoZSBoaWdoZXIgdGhlIGF2ZXJhZ2Ugc2lsaG91ZXR0ZSB3aWR0aCB0aGUgY2xvc2VyIHRoZSBvYmplY3RzIHdpdGhpbiB0aGUgc2FtZSBjbHVzdGVyIHRvIGVhY2ggb3RoZXIgYW5kIGFzIGZhciBhcyBwb3NzaWJsZSB0byB0aGUgb2JqZWN0cyBpbiB0aGUgb3RoZXIgY2x1c3Rlci4gIA0KQXQgdGhlIGVuZCwgYm90aCBtb2RlbHMgYXJlIGhlbHBmdWwgYW5kIGhlbHBlZCB1cyBpbiBwcmVkaWN0aW5nLiBCdXQgc2luY2Ugb3VyIGRhdGFzZXQgaXMgbnVtZXJpYyBhbmQgYWZ0ZXIgZG9pbmcgdGhlIGNsdXN0ZXJpbmcgYW5kIENsYXNzaWZpY2F0aW9uIHdlIGhhdmUgbm90aWNlZCB0aGF0IHRoZSBjbHVzdGVyaW5nIGZpdHMgbW9yZSBmb3IgdGhlIGRhdGFzZXQgYmVjYXVzZSBpdCdzIGNvbmNlcHQgYWxsIGFib3V0IHRoZSBudW1lcmljIGRhdGEuDQoNCiMgIDcuICBSZWZyZW5jZXMNCg0KDQoNCg==